Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java |
| index 97583b682427c1491325995f4a6fa8c3e7c6c11d..25073feb2384b26017de60828ef8eb1558da050c 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java |
| @@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable; |
| import android.net.Uri; |
| import android.os.AsyncTask; |
| import android.os.Build; |
| +import android.os.StrictMode; |
| import android.support.annotation.Nullable; |
| import android.support.v7.app.AlertDialog; |
| import android.text.TextUtils; |
| @@ -35,13 +36,16 @@ import android.view.View; |
| import android.widget.AdapterView; |
| import android.widget.AdapterView.OnItemClickListener; |
| +import org.chromium.base.ActivityState; |
| import org.chromium.base.ApiCompatibilityUtils; |
| import org.chromium.base.ApplicationState; |
| import org.chromium.base.ApplicationStatus; |
| +import org.chromium.base.ApplicationStatus.ActivityStateListener; |
| import org.chromium.base.Callback; |
| import org.chromium.base.ContextUtils; |
| import org.chromium.base.Log; |
| import org.chromium.base.StreamUtil; |
| +import org.chromium.base.ThreadUtils; |
| import org.chromium.base.VisibleForTesting; |
| import org.chromium.base.annotations.SuppressFBWarnings; |
| import org.chromium.base.metrics.RecordHistogram; |
| @@ -53,11 +57,14 @@ import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.Collections; |
| +import java.util.HashSet; |
| import java.util.List; |
| +import java.util.Set; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| + |
|
cco3
2017/01/31 01:32:57
remove
|
| /** |
| * A helper class that helps to start an intent to share titles and URLs. |
| */ |
| @@ -104,6 +111,12 @@ public class ShareHelper { |
| /** If non-null, will be used instead of the real activity. */ |
| private static FakeIntentReceiver sFakeIntentReceiverForTesting; |
| + /** Variables for adding options dynamically to app chooser*/ |
| + private static Set<Activity> sPendingShareActivities = |
| + Collections.synchronizedSet(new HashSet<Activity>()); |
| + private static ActivityStateListener sStateListener; |
| + private static AsyncTask<Void, Void, Void> sStateChangeTask; |
| + |
| private ShareHelper() {} |
| private static void fireIntent(Activity activity, Intent intent) { |
| @@ -681,4 +694,111 @@ public class ShareHelper { |
| if (packageName == null || className == null) return null; |
| return new ComponentName(packageName, className); |
| } |
| + |
| + /** |
| + * Dynamically add Chrome activities to Share chooser. |
| + * |
| + * @param activity The activity that will be triggering the share action. |
| + * @param callback The callback to be triggered after the options have been enabled. This |
|
mattreynolds
2017/01/31 18:59:31
javadoc (@param options)
|
| + * may or may not be synchronous depending on whether this will require |
| + * interacting with the Android framework. |
| + */ |
| + public static void enableOptions(final Activity activity, |
| + final List<Class> options, final Runnable callback) { |
| + ThreadUtils.assertOnUiThread(); |
| + |
| + if (sStateListener == null) { |
| + sStateListener = new ActivityStateListener() { |
| + @Override |
| + public void onActivityStateChange(Activity activity, int newState) { |
| + if (newState == ActivityState.PAUSED) return; |
| + unregisterActivity(activity, options); |
| + } |
| + }; |
| + } |
| + ApplicationStatus.registerStateListenerForAllActivities(sStateListener); |
| + boolean wasEmpty = sPendingShareActivities.isEmpty(); |
| + sPendingShareActivities.add(activity); |
| + |
| + waitForPendingStateChangeTask(); |
| + if (wasEmpty) { |
| + sStateChangeTask = new AsyncTask<Void, Void, Void>() { |
| + @Override |
| + protected Void doInBackground(Void... params) { |
| + if (sPendingShareActivities.isEmpty()) return null; |
| + |
| + for (int i = 0; i < options.size(); i++) { |
| + activity.getPackageManager().setComponentEnabledSetting( |
| + new ComponentName(activity, options.get(i)), |
| + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, |
| + PackageManager.DONT_KILL_APP); |
| + } |
| + |
| + return null; |
| + } |
| + |
| + @Override |
| + protected void onPostExecute(Void result) { |
| + if (sStateChangeTask == this) { |
| + sStateChangeTask = null; |
| + } else { |
| + waitForPendingStateChangeTask(); |
| + } |
| + callback.run(); |
| + } |
| + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| + } else { |
| + callback.run(); |
| + } |
| + } |
| + |
| + private static void unregisterActivity(final Activity activity, |
| + final List<Class> options) { |
| + ThreadUtils.assertOnUiThread(); |
| + |
| + sPendingShareActivities.remove(activity); |
| + if (!sPendingShareActivities.isEmpty()) return; |
| + ApplicationStatus.unregisterActivityStateListener(sStateListener); |
| + |
| + waitForPendingStateChangeTask(); |
| + sStateChangeTask = new AsyncTask<Void, Void, Void>() { |
| + @Override |
| + protected Void doInBackground(Void... params) { |
| + if (!sPendingShareActivities.isEmpty()) return null; |
| + |
| + for (int i = 0; i < options.size(); i++) { |
| + activity.getPackageManager().setComponentEnabledSetting( |
|
mattreynolds
2017/01/31 18:59:31
fix indent
|
| + new ComponentName(activity, options.get(i)), |
| + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, |
| + PackageManager.DONT_KILL_APP); |
| + } |
| + return null; |
| + } |
| + |
| + @Override |
| + protected void onPostExecute(Void result) { |
| + if (sStateChangeTask == this) sStateChangeTask = null; |
| + } |
| + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| + } |
| + |
| + /** |
| + * Waits for any pending state change operations to be completed. |
| + * |
| + * This will avoid timing issues described here: crbug.com/649453. |
| + */ |
| + public static void waitForPendingStateChangeTask() { |
| + ThreadUtils.assertOnUiThread(); |
| + |
| + if (sStateChangeTask == null) return; |
| + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); |
| + try { |
| + sStateChangeTask.get(); |
| + sStateChangeTask = null; |
| + } catch (InterruptedException | ExecutionException e) { |
| + Log.e(TAG, "Physical Web Share state change task did not complete as expected"); |
|
mattreynolds
2017/01/31 18:59:31
"Share Helper state change task..."
|
| + } finally { |
| + StrictMode.setThreadPolicy(oldPolicy); |
| + } |
| + } |
| } |