Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java

Issue 2666833002: Create entry to PWSharing through ShareHelper (Closed)
Patch Set: Cleaning up Chrome Activity more Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..f1aec61fa72e0e781c1e4a8b7194842ac34cd980 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,25 +36,34 @@ 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;
import org.chromium.chrome.R;
+import org.chromium.chrome.browser.physicalweb.PhysicalWebShareActivity;
+import org.chromium.chrome.browser.printing.PrintShareActivity;
+import org.chromium.chrome.browser.tab.Tab;
import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
import org.chromium.ui.UiUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
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;
@@ -104,6 +114,17 @@ 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;
+ public static final List<ShareActivity> sShareActivities = Collections.unmodifiableList(
+ new ArrayList<ShareActivity>() { {
cco3 2017/02/04 00:11:23 no extra space here
iankc 2017/02/06 23:53:29 Presubmit won't pass unless there is a space betwe
+ add(new PrintShareActivity());
+ add(new PhysicalWebShareActivity());
+ }});
+
private ShareHelper() {}
private static void fireIntent(Activity activity, Intent intent) {
@@ -681,4 +702,143 @@ 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 options List of ShareActivity to add to the chooser.
cco3 2017/02/04 00:11:23 currentTab
iankc 2017/02/06 23:53:29 Done.
+ * @param callback The callback to be triggered after the options have been enabled. This
+ * may or may not be synchronous depending on whether this will require
+ * interacting with the Android framework.
+ */
+ public static void enableShareActivitiesAndStartShareIntent(final Activity activity,
+ final Tab currentTab, final Runnable callback) {
+ ThreadUtils.assertOnUiThread();
+
+ if (sStateListener == null) {
+ sStateListener = new ActivityStateListener() {
+ @Override
+ public void onActivityStateChange(Activity activity, int newState) {
+ if (newState == ActivityState.PAUSED) return;
+ unregisterShareActivities(activity);
+ }
+ };
+ }
+ ApplicationStatus.registerStateListenerForAllActivities(sStateListener);
+ boolean wasEmpty = sPendingShareActivities.isEmpty();
+ sPendingShareActivities.add(activity);
+
+ final List<ShareActivity> options = getEnabledShareActivities(currentTab);
+ if (options.isEmpty()) {
+ callback.run();
cco3 2017/02/04 00:11:23 return after this, then decrease the indent afterw
iankc 2017/02/06 23:53:29 Done.
+ } else {
+ waitForPendingStateChangeTask();
+ if (wasEmpty) {
cco3 2017/02/04 00:11:23 do if (!wasEmpty) and then run the callback and re
iankc 2017/02/06 23:53:29 Done.
+ 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).getClass()),
+ 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();
+ }
+ }
+ }
+
+ /**
+ * @param currentTab The current tab of the chrome activity.
cco3 2017/02/04 00:11:23 Add a summary line too, please.
iankc 2017/02/06 23:53:29 Done.
+ * @return list of all share activities to be enabled.
cco3 2017/02/04 00:11:23 List of all enabled ShareActivities.
iankc 2017/02/06 23:53:29 Done.
+ */
+ public static List<ShareActivity> getEnabledShareActivities(final Tab currentTab) {
+ return filterEnabledShareActivities(sShareActivities, currentTab);
+ }
+
+ /**
+ * @param potentialOptions List of the potential ShareActivities to enable.
+ * @param currentTab The current tab of the chrome activity.
+ * @return Filtered list of options to enable for share chooser.
+ */
+ private static List<ShareActivity> filterEnabledShareActivities(
+ List<ShareActivity> potentialOptions, final Tab currentTab) {
cco3 2017/02/04 00:11:23 Why is the first parameter needed? Why does the t
iankc 2017/02/06 23:53:29 Done.
+ List<ShareActivity> enabledShareActivities = new ArrayList<ShareActivity>(2);
+ for (ShareActivity p: potentialOptions) {
cco3 2017/02/04 00:11:23 Use something like `activity` or `option` instead
iankc 2017/02/06 23:53:29 Done.
+ if (p.featureIsEnabled(currentTab)) {
+ enabledShareActivities.add(p);
+ }
+ }
+ return enabledShareActivities;
+ }
+
+ /**
+ * Disables Components after Share Chooser is done.
+ */
+ public static void unregisterShareActivities(final Activity activity) {
+ ThreadUtils.assertOnUiThread();
+
+ sPendingShareActivities.remove(activity);
+ if (!sPendingShareActivities.isEmpty()) return;
+ ApplicationStatus.unregisterActivityStateListener(sStateListener);
+
+ waitForPendingStateChangeTask();
+ sStateChangeTask = new AsyncTask<Void, Void, Void>() {
cco3 2017/02/04 00:11:23 Could we split this off into an internal class so
iankc 2017/02/06 23:53:29 Done.
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (!sPendingShareActivities.isEmpty()) return null;
+
+ for (int i = 0; i < sShareActivities.size(); i++) {
+ activity.getPackageManager().setComponentEnabledSetting(
+ new ComponentName(activity,
+ sShareActivities.get(i).getClass()),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ }
cco3 2017/02/04 00:11:23 is this lined up?
iankc 2017/02/06 23:53:29 Done.
+ 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() {
cco3 2017/02/04 00:11:23 Does this need to be public?
iankc 2017/02/06 23:53:29 Done.
+ ThreadUtils.assertOnUiThread();
+
+ if (sStateChangeTask == null) return;
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ sStateChangeTask.get();
+ sStateChangeTask = null;
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(TAG, "Share Helper state change task did not complete as expected");
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698