diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml index 34a2ce7..3b4762d 100644 --- a/app/AndroidManifest.xml +++ b/app/AndroidManifest.xml @@ -137,10 +137,27 @@ + - - + + + + + + + + + + + + + + - - - - - + + + - - + + - - - - - + + + > paramCache = Maps.newHashMap(); + private Consumer nextAction = null; + + public boolean isGooglePlayServicesAvailable() { + // return + // GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == + // ConnectionResult.SUCCESS; + return false; + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -224,7 +235,6 @@ public class MainActivity extends UnityPlayerActivity if (response != null || ex != null) { mAuthStateManager.updateAfterAuthorization(response, ex); } - if (response != null && response.authorizationCode != null) { // authorization code exchange is required mAuthStateManager.updateAfterAuthorization(response, ex); @@ -236,12 +246,10 @@ public class MainActivity extends UnityPlayerActivity } break; case RC_SIGN_IN: - Task task = GoogleSignIn.getSignedInAccountFromIntent(data); - handleSignInResult(task); + handleSignInResult(GoogleSignIn.getSignedInAccountFromIntent(data)); break; case FILE_SELECTOR_CODE: - Uri uri = data.getData(); - shareToTikTok(funId, uri); + shareToTikTok(funId, data.getData()); break; case RC_REQUEST_DRIVE_TO_UPLOAD: mExecutor.submit(this::saveToDriveAppFolder); @@ -418,7 +426,7 @@ public class MainActivity extends UnityPlayerActivity // end of qrcode public void signWithGoogle(String funId) { this.funId = funId; - if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { + if (isGooglePlayServicesAvailable()) { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this); if (account != null) { Log.w(TAG, "already login: " + account.getIdToken()); @@ -429,22 +437,18 @@ public class MainActivity extends UnityPlayerActivity startActivityForResult(signInIntent, RC_SIGN_IN); } } else { -// Log.i(TAG, "no gms, use app auth"); + Log.d(TAG, "no gms, use app auth"); AuthState state = mAuthStateManager.getCurrent(); - if (state.isAuthorized() && state.getIdToken() != null) { - Log.w(TAG, "getNeedsTokenRefresh: " + state.getNeedsTokenRefresh()); + if (state.isAuthorized()) { if (state.getNeedsTokenRefresh()) { Log.w(TAG, "need refresh accessToken"); - TokenRequest tokenRequest = state.createTokenRefreshRequest(); - performTokenRequest( - tokenRequest, - this::handleCodeExchangeResponse); + performTokenRequest(state.createTokenRefreshRequest(), this::handleCodeExchangeResponse); } else { - Log.w(TAG, "already login, accessToken not expired"); - Log.w(TAG, "id token : " + state.getIdToken()); + Log.w(TAG, "already login, accessToken not expired, id token:: " + state.getIdToken()); JcSDK.nativeCb(this.funId, null, state.getIdToken()); } } else { + Log.w(TAG, "not login"); mExecutor.submit(this::doAuth); } } @@ -556,14 +560,12 @@ public class MainActivity extends UnityPlayerActivity ResponseTypeValues.CODE, mConfiguration.getRedirectUri()) // apple need `form_post` when authorization_scope has `name email ` -// .setResponseMode("form_post") -// .setResponseType("code id_token") + // .setResponseMode("form_post") + // .setResponseType("code id_token") .setScope(mConfiguration.getScope()); - if (!TextUtils.isEmpty(loginHint)) { authRequestBuilder.setLoginHint(loginHint); } - mAuthRequest.set(authRequestBuilder.build()); } @@ -571,7 +573,9 @@ public class MainActivity extends UnityPlayerActivity mAuthIntentLatch = new CountDownLatch(1); mExecutor.execute(() -> { Log.i(TAG, "Warming up browser instance for auth request"); - CustomTabsIntent.Builder intentBuilder = mAuthService.createCustomTabsIntentBuilder(mAuthRequest.get().toUri()); + Uri uri = mAuthRequest.get().toUri(); + Log.i(TAG, "URI: " + uri); + CustomTabsIntent.Builder intentBuilder = mAuthService.createCustomTabsIntentBuilder(uri); mAuthIntent.set(intentBuilder.build()); mAuthIntentLatch.countDown(); }); @@ -706,25 +710,27 @@ public class MainActivity extends UnityPlayerActivity callback); } + private void checkAuthStateAndCB() { + AuthState state = mAuthStateManager.getCurrent(); + Log.d(TAG, "login success, auth state: " + state.isAuthorized()); + Log.d(TAG, "id token : " + state.getIdToken()); + Log.d(TAG, "access token: " + state.getAccessToken()); + Log.d(TAG, "refresh token: " + state.getRefreshToken()); + mAuthStateManager.replace(state); + JcSDK.nativeCb(this.funId, null, state.getIdToken()); + } + @WorkerThread private void handleCodeExchangeResponse( @Nullable TokenResponse tokenResponse, @Nullable AuthorizationException authException) { - mAuthStateManager.updateAfterTokenResponse(tokenResponse, authException); if (!mAuthStateManager.getCurrent().isAuthorized()) { - final String message = "Authorization Code exchange failed" + final String message = "Authorization Code exchange failed: " + ((authException != null) ? authException.error : ""); - - // WrongThread inference is incorrect for lambdas - // noinspection WrongThread Log.d(TAG, message); } else { - AuthState state = mAuthStateManager.getCurrent(); - Log.d(TAG, "login success, auth state: " + state.isAuthorized()); - Log.d(TAG, "app auth idToken: " + state.getIdToken()); - mAuthStateManager.replace(state); - JcSDK.nativeCb(this.funId, null, state.getIdToken()); + checkAuthStateAndCB(); } } @@ -803,7 +809,7 @@ public class MainActivity extends UnityPlayerActivity public void shareWithFacebook(String content) { ShareLinkContent linkContent = new ShareLinkContent.Builder() - .setContentUrl(Uri.parse("https://www.baidu.com")) + .setContentUrl(Uri.parse("https://www.google.com")) .setQuote(content) .build(); ShareDialog.show(this, linkContent); @@ -904,6 +910,7 @@ public class MainActivity extends UnityPlayerActivity Log.i(TAG, "passStorageState with: " + account); } + @WorkerThread private void saveToDriveAppFolder() { Map params = paramCache.get(RC_REQUEST_DRIVE_TO_UPLOAD); if (params == null) { @@ -927,11 +934,11 @@ public class MainActivity extends UnityPlayerActivity Intent signInIntent = mGoogleSignInClient.getSignInIntent(); startActivityForResult(signInIntent, requestCode); } + public void storagePass(String funid, String account, String password) { - Log.i(TAG, String.format("storagePass with: %s | %s | %s", funid, account, password)); - String filePath; + Log.i(TAG, String.format("storagePass with: %s | %s", funid, account)); try { - filePath = WalletUtil.savePassToLocal(this, account, password); + WalletUtil.savePassToLocal(this, account, password); } catch (JSONException | IOException e) { Log.i(TAG, String.format("error storage pass to local, %s", e.getMessage())); JcSDK.nativeCb(funid, "error storage pass to local", null); @@ -955,6 +962,8 @@ public class MainActivity extends UnityPlayerActivity // startActivity(intent); // }); } + + @WorkerThread private void loadDrivePass() { Map params = paramCache.get(RC_REQUEST_DRIVE_TO_READ); if (params == null) { @@ -964,22 +973,52 @@ public class MainActivity extends UnityPlayerActivity WalletUtil.getPassLocal(this, params.get("funid"), params.get("account")); paramCache.remove(RC_REQUEST_DRIVE_TO_READ); } + public void authGetStoragePass(String funid, String account) { Log.i(TAG, "authGetStoragePass with: " + account); - if (!WalletUtil.localCfgExists(this, account)) { - if (!GoogleSignIn.hasPermissions( - GoogleSignIn.getLastSignedInAccount(getActivity()), - new Scope(DriveScopes.DRIVE_APPDATA))) { - loginAndRequestDrivePermission(funid, account, RC_REQUEST_DRIVE_TO_READ); + if (isGooglePlayServicesAvailable()) { + if (!WalletUtil.localCfgExists(this, account)) { + if (!GoogleSignIn.hasPermissions( + GoogleSignIn.getLastSignedInAccount(getActivity()), + new Scope(DriveScopes.DRIVE_APPDATA))) { + loginAndRequestDrivePermission(funid, account, RC_REQUEST_DRIVE_TO_READ); + } else { + WalletUtil.downloadCfgToLocal(funid, account); + WalletUtil.getPassLocal(this, funid, account); + } } else { - WalletUtil.downloadCfgToLocal(funid, account); WalletUtil.getPassLocal(this, funid, account); } } else { - WalletUtil.getPassLocal(this, funid, account); + if (!WalletUtil.localCfgExists(this, account)) { + AuthState state = mAuthStateManager.getCurrent(); + WalletUtil.downloadCfgWithApi(funid, account, state.getAccessToken()); + WalletUtil.getPassLocal(this, funid, account); + // TODO:: + // 1. check whether the google account has been logged in, this situation occurs + // when non-google login + // 2. check if already had permission of drive appdata, add permission of drive + // appdata to auth_config + // 3. check if need refresh access token + // if (state.isAuthorized()) { + // if (state.getNeedsTokenRefresh()) { + // Log.d(TAG, "need refresh accessToken"); + // performTokenRequest(state.createTokenRefreshRequest(), + // this::handleCodeExchangeResponse); + // } else { + // Log.d(TAG, "access token no need refresh"); + // WalletUtil.downloadCfgToLocal(funid, account); + // WalletUtil.getPassLocal(this, funid, account); + // } + // } else { + // Log.w(TAG, "not login"); + // mExecutor.submit(this::doAuth); + // } + } else { + WalletUtil.getPassLocal(this, funid, account); + } } - // runOnUiThread(() -> { // Intent intent = new Intent(this, BiometricActivity.class); // intent.putExtra("action", "decrypt"); diff --git a/app/src/com/cege/games/release/wallet/WalletUtil.java b/app/src/com/cege/games/release/wallet/WalletUtil.java index 93f9826..1650576 100644 --- a/app/src/com/cege/games/release/wallet/WalletUtil.java +++ b/app/src/com/cege/games/release/wallet/WalletUtil.java @@ -17,6 +17,7 @@ import com.jc.jcfw.JcSDK; import com.jc.jcfw.NativeResult; import com.jc.jcfw.security.BiometricResult; import com.jc.jcfw.util.DriveUtils; +import com.jc.jcfw.util.DriverApiUtils; import com.jc.jcfw.util.FileUtils; import org.json.JSONException; @@ -114,13 +115,13 @@ public class WalletUtil { String fileName = generateFileName(account); String fileId = DriveUtils.queryOneAppFile(service, fileName); - if (Strings.isNullOrEmpty(fileId)) { Log.i(TAG, "file not found in drive"); return; } boolean downloadSuccess = false; - while (!downloadSuccess) { + int count = 0; + while (!downloadSuccess && count++ < 10) { try { String jsonStr = DriveUtils.downloadFile(service, fileId); File fileLocal = getWalletCfgFile(context, account); @@ -130,9 +131,23 @@ public class WalletUtil { Log.i(TAG, "error download file"); } } - - } - + public static void downloadCfgWithApi(String funid, String account, String accesToken) { + Context context = MainActivity.app; + DriverApiUtils api = new DriverApiUtils(accesToken); + String fileName = generateFileName(account); + try { + String fileId = api.queryOneAppFile(fileName); + if (Strings.isNullOrEmpty(fileId)) { + Log.i(TAG, "file not found in drive"); + return; + } + String jsonStr = api.fileInfo(fileId); + File fileLocal = getWalletCfgFile(context, account); + FileUtils.writeFile(fileLocal, jsonStr); + } catch (IOException | JSONException e) { + Log.i(TAG, "error download file"); + } + } } diff --git a/app/src/com/jc/jcfw/JcSDK.java b/app/src/com/jc/jcfw/JcSDK.java index ad44fc7..2f49f42 100644 --- a/app/src/com/jc/jcfw/JcSDK.java +++ b/app/src/com/jc/jcfw/JcSDK.java @@ -164,12 +164,10 @@ public class JcSDK { } public static void storagePass(String funid, String account, String password) { - Log.i(TAG, "storagePass with: " + account); MainActivity.app.storagePass(funid, account, password); } public static void authGetStoragePass(String funid, String account) { - Log.i(TAG, "authGetStoragePass with: " + account); MainActivity.app.authGetStoragePass(funid, account); } diff --git a/app/src/com/jc/jcfw/util/DriverApiUtils.java b/app/src/com/jc/jcfw/util/DriverApiUtils.java new file mode 100644 index 0000000..eed2b2d --- /dev/null +++ b/app/src/com/jc/jcfw/util/DriverApiUtils.java @@ -0,0 +1,99 @@ +package com.jc.jcfw.util; + +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.IOException; + +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class DriverApiUtils { + private static final String driveApiBase = "https://www.googleapis.com/drive/v3/files"; + private final String TAG = getClass().getSimpleName(); + + private String token = ""; + + public DriverApiUtils() { + } + + public DriverApiUtils(String token) { + this.token = token; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public JSONArray fileList() throws IOException, JSONException { + OkHttpClient client = new OkHttpClient().newBuilder() + .build(); + Request request = new Request.Builder() + .url(driveApiBase + "?spaces=appDataFolder&fields=files(id, name, modifiedTime)") + .get() + .addHeader("Authorization", "Bearer " + token) + .build(); + try (Response response = client.newCall(request).execute()) { + String resStr = response.body().string(); + JSONObject resJson = new JSONObject(resStr); + return resJson.getJSONArray("files"); + } + } + + public String queryOneAppFile(String fileName) throws IOException, JSONException { + JSONArray fileList = fileList(); + for (int i = 0; i < fileList.length(); i++) { + JSONObject file = fileList.getJSONObject(i); + if (file.getString("name").equals(fileName)) { + return file.getString("id"); + } + } + return ""; + } + + public String fileInfo(String fileId) throws IOException { + OkHttpClient client = new OkHttpClient().newBuilder() + .build(); + Request request = new Request.Builder() + .url(String.format("%s/%s?alt=media", driveApiBase, fileId)) + .get() + .addHeader("Authorization", "Bearer " + token) + .build(); + try (Response response = client.newCall(request).execute()) { + return response.body().string(); + } + } + + public void createFile() throws IOException { + OkHttpClient client = new OkHttpClient().newBuilder() + .build(); + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM) + .addFormDataPart("", "upload-options.json", + RequestBody.create(MediaType.parse("application/octet-stream"), + new File("/Users/zhl/Desktop/drivetest/files/upload-options.json"))) + .addFormDataPart("", "wallet_1.json", + RequestBody.create(MediaType.parse("application/octet-stream"), + new File("/Users/zhl/Desktop/drivetest/files/wallet_1.json"))) + .build(); + Request request = new Request.Builder() + .url(driveApiBase + "?uploadType=multipart") + .post(body) + .addHeader("Content-Type", "application/json") + .addHeader("Authorization", "Bearer " + token) + .build(); + Response response = client.newCall(request).execute(); + } +}