package com.cege.games.release; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.text.TextUtils; import android.util.Log; import android.view.Window; import android.widget.Toast; import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import androidx.browser.customtabs.CustomTabsIntent; import androidx.core.app.ActivityOptionsCompat; import com.bytedance.sdk.open.tiktok.TikTokOpenApiFactory; import com.bytedance.sdk.open.tiktok.api.TikTokOpenApi; import com.bytedance.sdk.open.tiktok.authorize.model.Authorization; import com.bytedance.sdk.open.tiktok.base.MediaContent; import com.bytedance.sdk.open.tiktok.base.VideoObject; import com.bytedance.sdk.open.tiktok.share.Share; import com.cege.games.release.activity.CustomCaptureActivity; import com.cege.games.release.activity.WebPageActivity; import com.cege.games.release.apple.AppleLoginActivity; import com.cege.games.release.dialog.QRCodeActivity; import com.facebook.AccessToken; import com.facebook.CallbackManager; import com.facebook.FacebookCallback; import com.facebook.FacebookException; import com.facebook.appevents.AppEventsLogger; import com.facebook.login.LoginManager; import com.facebook.login.LoginResult; import com.facebook.share.model.ShareLinkContent; import com.facebook.share.widget.ShareDialog; import com.google.android.gms.auth.api.signin.GoogleSignIn; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInClient; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.Scopes; import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.Scope; import com.google.android.gms.tasks.Task; import com.google.firebase.analytics.FirebaseAnalytics; import com.jc.jcfw.JcSDK; import com.jc.jcfw.appauth.AuthStateManager; import com.jc.jcfw.appauth.JConfiguration; import com.jc.jcfw.util.FileUtils; import com.jc.jcfw.util.JsonUtils; import com.king.zxing.CameraScan; import com.king.zxing.util.CodeUtils; import com.king.zxing.util.LogUtils; import com.unity3d.player.UnityPlayerActivity; import net.openid.appauth.AppAuthConfiguration; import net.openid.appauth.AuthState; import net.openid.appauth.AuthorizationException; import net.openid.appauth.AuthorizationRequest; import net.openid.appauth.AuthorizationResponse; import net.openid.appauth.AuthorizationService; import net.openid.appauth.AuthorizationServiceConfiguration; import net.openid.appauth.ClientAuthentication; import net.openid.appauth.ClientSecretBasic; import net.openid.appauth.RegistrationRequest; import net.openid.appauth.RegistrationResponse; import net.openid.appauth.ResponseTypeValues; import net.openid.appauth.TokenRequest; import net.openid.appauth.TokenResponse; import net.openid.appauth.browser.AnyBrowserMatcher; import net.openid.appauth.browser.BrowserMatcher; import org.cocos2dx.lib.Cocos2dxHelper; import org.cocos2dx.lib.CocosJSHelper; import org.json.JSONException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import pub.devrel.easypermissions.AfterPermissionGranted; import pub.devrel.easypermissions.EasyPermissions; public class MainActivity extends UnityPlayerActivity implements Cocos2dxHelper.Cocos2dxHelperListener, EasyPermissions.PermissionCallbacks { private static final String TAG = MainActivity.class.getSimpleName(); public static MainActivity app; private Toast toast; public static final String KEY_TITLE = "key_title"; public static final String KEY_IS_CONTINUOUS = "key_continuous_scan"; // scan QRCode public static final int REQUEST_CODE_SCAN = 0X01; public static final int REQUEST_CODE_PHOTO = 0X02; // AppAuth private static final int RC_AUTH = 0X04; // google signin private static final int RC_SIGN_IN = 0X05; public static final int RC_CAMERA = 0X011; public static final int RC_READ_PHOTO = 0X012; public static final int FILE_SELECTOR_CODE = 0X014; private String title; private String funId; private String oid; private QRCodeActivity qrCodeActivity; // AppAuth private AuthorizationService mAuthService; private AuthStateManager mAuthStateManager; private JConfiguration mConfiguration; private ExecutorService mExecutor; private final AtomicReference mClientId = new AtomicReference<>(); private final AtomicReference mAuthRequest = new AtomicReference<>(); private final AtomicReference mAuthIntent = new AtomicReference<>(); private CountDownLatch mAuthIntentLatch = new CountDownLatch(1); private TikTokOpenApi tiktokOpenApi; public String getFunId() { return funId; } @NonNull private final BrowserMatcher mBrowserMatcher = AnyBrowserMatcher.INSTANCE; private GoogleSignInClient mGoogleSignInClient; // facebook login private CallbackManager mCallbackManager; private FirebaseAnalytics mFirebaseAnalytics; private AppEventsLogger fbLogger; @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); Log.i(TAG, "onCreate: " + getIntent().getDataString()); // Obtain the FirebaseAnalytics instance. mFirebaseAnalytics = FirebaseAnalytics.getInstance(this); onLoadNativeLibraries(); app = this; Cocos2dxHelper.init(this); CocosJSHelper.initJSEnv(getApplicationContext()); // begin of google sign GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.default_web_client_id1)) .requestScopes(new Scope(Scopes.EMAIL)) // .requestScopes(new Scope("https://www.googleapis.com/auth/drive.appdata")) .build(); mGoogleSignInClient = GoogleSignIn.getClient(this, gso); // end of google sign // begin of google oauth sign mExecutor = Executors.newSingleThreadExecutor(); mAuthStateManager = AuthStateManager.getInstance(this); mConfiguration = JConfiguration.getInstance(this); mExecutor.submit(this::initializeAppAuth); // end of google oauth sign // begin of facebook login initFacebookSDK(); // end of facebook login // ATTENTION: This was auto-generated to handle app links. // Intent appLinkIntent = getIntent(); // String appLinkAction = appLinkIntent.getAction(); // Uri appLinkData = appLinkIntent.getData(); tiktokOpenApi = TikTokOpenApiFactory.create(this); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); mCallbackManager.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && data != null) { switch (requestCode) { case REQUEST_CODE_SCAN: String result = CameraScan.parseScanResult(data); Log.i(TAG, "scan qrcode with funId: " + funId + " result: " + result); JcSDK.nativeCb(funId, null, result); funId = ""; break; case REQUEST_CODE_PHOTO: parsePhoto(data); break; case RC_AUTH: AuthorizationResponse response = AuthorizationResponse.fromIntent(data); AuthorizationException ex = AuthorizationException.fromIntent(data); if (response != null || ex != null) { mAuthStateManager.updateAfterAuthorization(response, ex); } if (response != null && response.authorizationCode != null) { // authorization code exchange is required mAuthStateManager.updateAfterAuthorization(response, ex); exchangeAuthorizationCode(response); } else if (ex != null) { Log.i(TAG, "Authorization flow failed: " + ex.getMessage()); } else { Log.i(TAG, "No authorization state retained - reauthorization required"); } break; case RC_SIGN_IN: Task task = GoogleSignIn.getSignedInAccountFromIntent(data); handleSignInResult(task); break; case FILE_SELECTOR_CODE: Uri uri = data.getData(); shareToTikTok(funId, uri); break; } } else { boolean next = false; if (requestCode == REQUEST_CODE_SCAN && data != null) { if (data.getBooleanExtra("localImg", false)) { startPhotoCode(this.funId); next = true; } } if (!next) { if (requestCode == RC_SIGN_IN) { Task task = GoogleSignIn.getSignedInAccountFromIntent(data); handleSignInResult(task); } if (requestCode == REQUEST_CODE_SCAN) { JcSDK.nativeCb(funId, "activity result with code: " + resultCode, null); } funId = ""; } } } private Context getContext() { return this; } @Override protected void onStart() { super.onStart(); if (mExecutor.isShutdown()) { mExecutor = Executors.newSingleThreadExecutor(); } } // begin for unity @Override protected void onNewIntent(Intent intent) { // To support deep linking, we need to make sure that the client can get access // to // the last sent intent. The clients access this through a JNI api that allows // them // to get the intent set on launch. To update that after launch we have to // manually // replace the intent with the one caught here. setIntent(intent); } protected void onLoadNativeLibraries() { try { ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); Bundle bundle = ai.metaData; String libName = bundle.getString("android.app.lib_name"); System.loadLibrary(libName); } catch (Exception e) { e.printStackTrace(); } } @Override public void showDialog(String pTitle, String pMessage) { } @Override public void runOnGLThread(Runnable pRunnable) { } /** begin of easypermissions */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // Forward results to EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override public void onPermissionsGranted(int requestCode, @NonNull List list) { // Some permissions have been granted } @Override public void onPermissionsDenied(int requestCode, @NonNull List list) { // Some permissions have been denied if ((requestCode == RC_CAMERA || requestCode == RC_READ_PHOTO) && null != funId && !"".equals(funId)) { JcSDK.nativeCb(funId, "User cancel", null); funId = ""; } } // end of easypermissions // begin of qrcode /** * check if had permission for camera */ @AfterPermissionGranted(RC_CAMERA) private void checkCameraPermissions() { String[] perms = { Manifest.permission.CAMERA }; if (EasyPermissions.hasPermissions(this, perms)) { startScan(title); } else { // Do not have permissions, request them now EasyPermissions.requestPermissions(this, getString(R.string.permission_camera), RC_CAMERA, perms); } } /** * scan qrcode */ private void startScan(String title) { ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.in, R.anim.out); Intent intent = new Intent(this, CustomCaptureActivity.class); // Intent intent = new Intent(this, CaptureActivity.class); intent.putExtra(KEY_TITLE, title); intent.putExtra(KEY_IS_CONTINUOUS, false); runOnUiThread(() -> { this.startActivityForResult(intent, REQUEST_CODE_SCAN, optionsCompat.toBundle()); }); } private void asyncThread(Runnable runnable) { new Thread(runnable).start(); } private void parsePhoto(Intent data) { try { Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData()); parsePhotoData(bitmap); } catch (Exception e) { e.printStackTrace(); JcSDK.nativeCb(funId, e.toString(), null); funId = ""; } } private void parsePhotoData(Bitmap bitmap) { asyncThread(() -> { final String result = CodeUtils.parseQRCode(bitmap); if (null == result || "".equals(result)) { JcSDK.nativeCb(funId, "no qrdeata", null); } else { LogUtils.d("result:" + result); JcSDK.nativeCb(funId, null, result); } funId = ""; }); } public void showQRScan(String funId, String title) { this.title = title; this.funId = funId; checkCameraPermissions(); } /** * start image scan */ public void startPhotoCode(String funId) { Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startActivityForResult(pickIntent, REQUEST_CODE_PHOTO); } // end of qrcode public void signWithGoogle(String funId) { this.funId = funId; if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this); if (account != null) { Log.w(TAG, "already login: " + account.getIdToken()); mGoogleSignInClient.silentSignIn() .addOnCompleteListener(this, this::handleSignInResult); } else { Intent signInIntent = mGoogleSignInClient.getSignInIntent(); startActivityForResult(signInIntent, RC_SIGN_IN); } } else { Log.i(TAG, "no gms, use app auth"); AuthState state = mAuthStateManager.getCurrent(); if (state.isAuthorized() && state.getIdToken() != null) { Log.w(TAG, "getNeedsTokenRefresh: " + state.getNeedsTokenRefresh()); if (state.getNeedsTokenRefresh()) { Log.w(TAG, "need refresh accessToken"); TokenRequest tokenRequest = state.createTokenRefreshRequest(); performTokenRequest( tokenRequest, this::handleCodeExchangeResponse); } else { Log.w(TAG, "already login, accessToken not expired"); Log.w(TAG, "id token : " + state.getIdToken()); runOnUiThread(() -> successSdkCb(state.getIdToken())); } } else { mExecutor.submit(this::doAuth); } } } public void signOutGoogle(String funId) { mGoogleSignInClient.signOut() .addOnCompleteListener(this, task -> { // ... }); } private void handleSignInResult(Task completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); Log.w(TAG, "signIn success: "); Log.w(TAG, "gsa idToken: " + account.getIdToken()); runOnUiThread(() -> successSdkCb(account.getIdToken())); // Signed in successfully, show authenticated UI. } catch (ApiException e) { // The ApiException status code indicates the detailed failure reason. // Please refer to the GoogleSignInStatusCodes class reference for more // information. Log.w(TAG, "signInResult:failed code=" + e.getStatusCode()); } } // begin of AppAuth /** * Initializes the authorization service configuration if necessary, either from * the local * static values or by retrieving an OpenID discovery document. */ @WorkerThread private void initializeAppAuth() { Log.i(TAG, "Initializing AppAuth"); recreateAuthorizationService(); if (mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration() != null) { // configuration is already created, skip to client initialization Log.i(TAG, "auth config already established"); initializeClient(); return; } // if we are not using discovery, build the authorization service configuration // directly // from the static configuration values. if (mConfiguration.getDiscoveryUri() == null) { Log.i(TAG, "Creating auth config from res/raw/auth_config.json"); AuthorizationServiceConfiguration config = new AuthorizationServiceConfiguration( mConfiguration.getAuthEndpointUri(), mConfiguration.getTokenEndpointUri(), mConfiguration.getRegistrationEndpointUri(), mConfiguration.getEndSessionEndpoint()); mAuthStateManager.replace(new AuthState(config)); initializeClient(); return; } // WrongThread inference is incorrect for lambdas // noinspection WrongThread Log.i(TAG, "Retrieving OpenID discovery doc"); AuthorizationServiceConfiguration.fetchFromUrl( mConfiguration.getDiscoveryUri(), this::handleConfigurationRetrievalResult, mConfiguration.getConnectionBuilder()); } @MainThread private void handleConfigurationRetrievalResult( AuthorizationServiceConfiguration config, AuthorizationException ex) { if (config == null) { Log.i(TAG, "Failed to retrieve discovery document", ex); return; } Log.i(TAG, "Discovery document retrieved"); mAuthStateManager.replace(new AuthState(config)); mExecutor.submit(this::initializeClient); } private void recreateAuthorizationService() { if (mAuthService != null) { Log.i(TAG, "Discarding existing AuthService instance"); mAuthService.dispose(); } mAuthService = createAuthorizationService(); mAuthRequest.set(null); mAuthIntent.set(null); } private AuthorizationService createAuthorizationService() { Log.i(TAG, "Creating authorization service"); AppAuthConfiguration.Builder builder = new AppAuthConfiguration.Builder(); builder.setBrowserMatcher(mBrowserMatcher); builder.setConnectionBuilder(mConfiguration.getConnectionBuilder()); return new AuthorizationService(this, builder.build()); } private void createAuthRequest(@Nullable String loginHint) { Log.i(TAG, "Creating auth request for login hint: " + loginHint); AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder( mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(), mClientId.get(), ResponseTypeValues.CODE, mConfiguration.getRedirectUri()) .setScope(mConfiguration.getScope()); if (!TextUtils.isEmpty(loginHint)) { authRequestBuilder.setLoginHint(loginHint); } mAuthRequest.set(authRequestBuilder.build()); } private void warmUpBrowser() { mAuthIntentLatch = new CountDownLatch(1); mExecutor.execute(() -> { Log.i(TAG, "Warming up browser instance for auth request"); CustomTabsIntent.Builder intentBuilder = mAuthService.createCustomTabsIntentBuilder(mAuthRequest.get().toUri()); mAuthIntent.set(intentBuilder.build()); mAuthIntentLatch.countDown(); }); } @MainThread private void initializeAuthRequest() { createAuthRequest(""); warmUpBrowser(); displayAuthOptions(); } /** * Initiates a dynamic registration request if a client ID is not provided by * the static * configuration. */ @WorkerThread private void initializeClient() { if (mConfiguration.getClientId() != null) { Log.i(TAG, "Using static client ID: " + mConfiguration.getClientId()); // use a statically configured client ID mClientId.set(mConfiguration.getClientId()); runOnUiThread(this::initializeAuthRequest); return; } RegistrationResponse lastResponse = mAuthStateManager.getCurrent().getLastRegistrationResponse(); if (lastResponse != null) { Log.i(TAG, "Using dynamic client ID: " + lastResponse.clientId); // already dynamically registered a client ID mClientId.set(lastResponse.clientId); runOnUiThread(this::initializeAuthRequest); return; } // WrongThread inference is incorrect for lambdas // noinspection WrongThread Log.i(TAG, "Dynamically registering client"); RegistrationRequest registrationRequest = new RegistrationRequest.Builder( mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(), Collections.singletonList(mConfiguration.getRedirectUri())) .setTokenEndpointAuthenticationMethod(ClientSecretBasic.NAME) .build(); mAuthService.performRegistrationRequest( registrationRequest, this::handleRegistrationResponse); } private void handleRegistrationResponse( RegistrationResponse response, AuthorizationException ex) { mAuthStateManager.updateAfterRegistration(response, ex); if (response == null) { Log.i(TAG, "Failed to dynamically register client", ex); return; } Log.i(TAG, "Dynamically registered client: " + response.clientId); mClientId.set(response.clientId); initializeAuthRequest(); } private void displayAuthOptions() { AuthState state = mAuthStateManager.getCurrent(); AuthorizationServiceConfiguration config = state.getAuthorizationServiceConfiguration(); String authEndpointStr; if (config.discoveryDoc != null) { authEndpointStr = "Discovered auth endpoint: \n"; } else { authEndpointStr = "Static auth endpoint: \n"; } authEndpointStr += config.authorizationEndpoint; Log.i(TAG, authEndpointStr); String clientIdStr; if (state.getLastRegistrationResponse() != null) { clientIdStr = "Dynamic client ID: \n"; } else { clientIdStr = "Static client ID: \n"; } clientIdStr += mClientId; Log.i(TAG, clientIdStr); } /** * Performs the authorization request, using the browser selected in the * spinner, * and a user-provided `login_hint` if available. */ @WorkerThread private void doAuth() { try { mAuthIntentLatch.await(); } catch (InterruptedException ex) { Log.w(TAG, "Interrupted while waiting for auth intent"); } Intent intent = mAuthService.getAuthorizationRequestIntent( mAuthRequest.get(), mAuthIntent.get()); startActivityForResult(intent, RC_AUTH); } @MainThread private void exchangeAuthorizationCode(AuthorizationResponse authorizationResponse) { Log.d(TAG, "Exchanging authorization code"); performTokenRequest( authorizationResponse.createTokenExchangeRequest(), this::handleCodeExchangeResponse); } @MainThread private void performTokenRequest( TokenRequest request, AuthorizationService.TokenResponseCallback callback) { ClientAuthentication clientAuthentication; try { clientAuthentication = mAuthStateManager.getCurrent().getClientAuthentication(); } catch (ClientAuthentication.UnsupportedAuthenticationMethod ex) { Log.d(TAG, "Token request cannot be made, client authentication for the token " + "endpoint could not be constructed (%s)", ex); return; } mAuthService.performTokenRequest( request, clientAuthentication, callback); } @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" + ((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); runOnUiThread(() -> successSdkCb(state.getIdToken())); } } @MainThread private void successSdkCb(String idToken) { JcSDK.nativeCb(this.funId, null, idToken); } @MainThread private void errorSdkCb(String errMsg) { JcSDK.nativeCb(this.funId, errMsg, null); } // sign with tiktok public void signWithTiktok(String funId) { this.funId = funId; Log.i(TAG, "login with tiktok: " + funId); // STEP 1: Create an instance of TiktokOpenApi // STEP 2: Create an instance of Authorization.Request and set parameters Authorization.Request request = new Authorization.Request(); request.scope = "user.info.basic,video.list"; request.state = funId; tiktokOpenApi.authorize(request); } public void showQRCode(String funid, String str, String title, String oid) { runOnUiThread(() -> { if (qrCodeActivity == null) { qrCodeActivity = new QRCodeActivity(getContext()); } qrCodeActivity.showQRCode(str, title, oid); qrCodeActivity.show(); }); } public void showToast(String text) { runOnUiThread(() -> { if (toast == null) { toast = Toast.makeText(this, text, Toast.LENGTH_SHORT); } else { toast.setDuration(Toast.LENGTH_SHORT); toast.setText(text); } toast.show(); }); } // begin of facebook login private void initFacebookSDK() { mCallbackManager = CallbackManager.Factory.create(); fbLogger = AppEventsLogger.newLogger(this); LoginManager.getInstance().registerCallback(mCallbackManager, new FacebookCallback() { @Override public void onSuccess(LoginResult loginResult) { AccessToken accessToken = AccessToken.getCurrentAccessToken(); Log.d(TAG, "Login Success:: accessToken: " + accessToken.getToken()); if (!verifyFbAccessToken(accessToken)) { runOnUiThread(() -> errorSdkCb("access token expired")); } } @Override public void onCancel() { Log.d(TAG, "Login cancel"); runOnUiThread(() -> errorSdkCb("user login cancel")); } @Override public void onError(FacebookException exception) { Log.i(TAG, "Login error: " + exception.getMessage()); runOnUiThread(() -> errorSdkCb(exception.getMessage())); } }); } public void signWithFacebook(String funId) { Log.i(TAG, "login with facebook: " + funId); this.funId = funId; AccessToken accessToken = AccessToken.getCurrentAccessToken(); // Log.d("Success", "Login:: accessToken: " + accessToken.getToken()); if (!verifyFbAccessToken(accessToken)) { LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "email")); } // AccessToken.getCurrentAccessToken(); } public void shareWithFacebook(String content) { ShareLinkContent linkContent = new ShareLinkContent.Builder() .setContentUrl(Uri.parse("https://www.baidu.com")) .setQuote(content) .build(); ShareDialog.show(this, linkContent); } private boolean verifyFbAccessToken(AccessToken accessToken) { boolean isLoggedIn = accessToken != null && !accessToken.isExpired(); if (isLoggedIn) { runOnUiThread(() -> successSdkCb(accessToken.getToken())); return true; } else { return false; } } // end of facebook login public void signWithTwitter(String funId) { Log.i(TAG, "login with twitter: " + funId); this.funId = funId; } public void logEvent(String content) { try { Bundle bundle = JsonUtils.convertJsonToBundle(content); String eventName = bundle.getString("name", "custom_event"); mFirebaseAnalytics.logEvent(eventName, bundle); fbLogger.logEvent(eventName, bundle); } catch (JSONException e) { Log.e(TAG, "log event JSONException: " + e.getMessage()); } catch (Exception e) { Log.e(TAG, "log event Exception: " + e.getMessage()); } } public void signWithApple(String funId) { this.funId = funId; Log.i(TAG, "login with apple: " + funId); runOnUiThread(() -> { Intent intent = new Intent(this, AppleLoginActivity.class); intent.putExtra("funId", funId); startActivity(intent); }); } public void showPage(String fid, final String url) { runOnUiThread(() -> { Log.i(TAG, "show page: " + url); Intent intent = new Intent(this, WebPageActivity.class); intent.putExtra("url", url); startActivity(intent); // picker video file and share to tiktok // openFileSelector(); }); } public void shareToTikTok(String funId, Uri uriToImage) { this.funId = funId; grantUriPermission("com.zhiliaoapp.musically", uriToImage, Intent.FLAG_GRANT_READ_URI_PERMISSION); grantUriPermission("com.ss.android.ugc.trill", uriToImage, Intent.FLAG_GRANT_READ_URI_PERMISSION); Log.i(TAG, "share to tiktok: " + uriToImage.toString()); if (tiktokOpenApi.isShareSupportFileProvider()) { Share.Request request = new Share.Request(); ArrayList mUri = new ArrayList<>(); mUri.add(uriToImage.toString()); VideoObject videoObject = new VideoObject(); videoObject.mVideoPaths = mUri; MediaContent content = new MediaContent(); content.mMediaObject = videoObject; // 3.set required parameters request.mMediaContent = content; request.mState = funId; request.mShareFormat = Share.Format.DEFAULT; tiktokOpenApi.share(request); } // share with Android ShareSheet // runOnUiThread(() -> { // Log.i(TAG, "share to tiktok: " + uriToImage); // Intent shareIntent = new Intent(); // shareIntent.setAction(Intent.ACTION_SEND); // shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage); // shareIntent.setType("video/*"); // startActivity(Intent.createChooser(shareIntent, "share")); // }); } /** * 打开本地文件器 */ private void openFileSelector() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("video/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(intent, FILE_SELECTOR_CODE); } }