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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/share/OptionalShareTargetsManager.java

Issue 2694103002: Create OptionalShareTargetsManager (Closed)
Patch Set: Fixing Teds comments 1 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.printing; 5 package org.chromium.chrome.browser.share;
6 6
7 import android.app.Activity; 7 import android.app.Activity;
8 import android.content.ComponentName; 8 import android.content.ComponentName;
9 import android.content.Intent;
10 import android.content.pm.PackageManager; 9 import android.content.pm.PackageManager;
11 import android.os.AsyncTask; 10 import android.os.AsyncTask;
12 import android.os.Bundle;
13 import android.os.StrictMode; 11 import android.os.StrictMode;
14 import android.support.v7.app.AppCompatActivity;
15 12
16 import org.chromium.base.ActivityState; 13 import org.chromium.base.ActivityState;
17 import org.chromium.base.ApplicationStatus; 14 import org.chromium.base.ApplicationStatus;
18 import org.chromium.base.ApplicationStatus.ActivityStateListener; 15 import org.chromium.base.ApplicationStatus.ActivityStateListener;
19 import org.chromium.base.Log; 16 import org.chromium.base.Log;
20 import org.chromium.base.ThreadUtils; 17 import org.chromium.base.ThreadUtils;
21 import org.chromium.chrome.R;
22 import org.chromium.chrome.browser.ChromeActivity;
23 import org.chromium.chrome.browser.share.ShareHelper;
24 import org.chromium.chrome.browser.util.IntentUtils;
25 18
26 import java.lang.ref.WeakReference; 19 import java.util.ArrayList;
27 import java.util.Collections; 20 import java.util.Collections;
28 import java.util.HashSet; 21 import java.util.HashSet;
29 import java.util.List; 22 import java.util.List;
30 import java.util.Set; 23 import java.util.Set;
31 import java.util.concurrent.ExecutionException; 24 import java.util.concurrent.ExecutionException;
32 25
33 /** 26 /**
34 * A simple activity that allows Chrome to expose print as an option in the shar e menu. 27 * A manager for optional share activities in the share picker intent.
35 */ 28 */
36 public class PrintShareActivity extends AppCompatActivity { 29 public class OptionalShareTargetsManager {
37 30 private static final String TAG = "share_manager";
38 private static final String TAG = "cr_printing";
39 31
40 private static Set<Activity> sPendingShareActivities = 32 private static Set<Activity> sPendingShareActivities =
41 Collections.synchronizedSet(new HashSet<Activity>()); 33 Collections.synchronizedSet(new HashSet<Activity>());
42 private static ActivityStateListener sStateListener; 34 private static ActivityStateListener sStateListener;
43 private static AsyncTask<Void, Void, Void> sStateChangeTask; 35 private static AsyncTask<Void, Void, Void> sStateChangeTask;
36 private static List<ComponentName> sEnabledComponents;
44 37
45 /** 38 /**
46 * Enable the print sharing option. 39 * Enables sharing options.
47 * 40 * @param triggeringActivity The activity that will be triggering the share action. The
48 * @param activity The activity that will be triggering the share action. T he activitiy's 41 * activity's state will be tracked to disable the options w hen
49 * state will be tracked to disable the print option when th e share operation 42 * the share operation has been completed.
50 * has been completed. 43 * @param enabledClasses classes to be enabled.
51 * @param callback The callback to be triggered after the print option has b een enabled. This 44 * @param callback The callback to be triggered after the options have been enabled. This
52 * may or may not be synchronous depending on whether this w ill require 45 * may or may not be synchronous depending on whether this w ill require
53 * interacting with the Android framework. 46 * interacting with the Android framework.
54 */ 47 */
55 public static void enablePrintShareOption(final Activity activity, final Run nable callback) { 48 public static void enableOptionalShareActivities(final Activity triggeringAc tivity,
49 final List<Class<? extends Activity>> enabledClasses, final Runnable callback) {
56 ThreadUtils.assertOnUiThread(); 50 ThreadUtils.assertOnUiThread();
57 51
58 if (sStateListener == null) { 52 if (sStateListener == null) {
59 sStateListener = new ActivityStateListener() { 53 sStateListener = new ActivityStateListener() {
60 @Override 54 @Override
61 public void onActivityStateChange(Activity activity, int newStat e) { 55 public void onActivityStateChange(Activity triggeringActivity, i nt newState) {
62 if (newState == ActivityState.PAUSED) return; 56 if (newState == ActivityState.PAUSED) return;
63 unregisterActivity(activity); 57 handleShareFinish(triggeringActivity);
64 } 58 }
65 }; 59 };
66 } 60 }
67 ApplicationStatus.registerStateListenerForAllActivities(sStateListener); 61 ApplicationStatus.registerStateListenerForAllActivities(sStateListener);
68 boolean wasEmpty = sPendingShareActivities.isEmpty(); 62 boolean wasEmpty = sPendingShareActivities.isEmpty();
69 sPendingShareActivities.add(activity); 63 sPendingShareActivities.add(triggeringActivity);
70 64
71 waitForPendingStateChangeTask(); 65 waitForPendingStateChangeTask();
72 if (wasEmpty) { 66 if (wasEmpty) {
67 // Note: possible race condition if two calls to this method happen simultaneously.
73 sStateChangeTask = new AsyncTask<Void, Void, Void>() { 68 sStateChangeTask = new AsyncTask<Void, Void, Void>() {
74 @Override 69 @Override
75 protected Void doInBackground(Void... params) { 70 protected Void doInBackground(Void... params) {
76 if (sPendingShareActivities.isEmpty()) return null; 71 if (sPendingShareActivities.isEmpty()) return null;
77 72 sEnabledComponents = new ArrayList<>(enabledClasses.size());
78 activity.getPackageManager().setComponentEnabledSetting( 73 for (int i = 0; i < enabledClasses.size(); i++) {
79 new ComponentName(activity, PrintShareActivity.class ), 74 ComponentName newEnabledComponent =
80 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 75 new ComponentName(triggeringActivity, enabledCla sses.get(i));
81 PackageManager.DONT_KILL_APP); 76 triggeringActivity.getPackageManager().setComponentEnabl edSetting(
77 newEnabledComponent, PackageManager.COMPONENT_EN ABLED_STATE_ENABLED,
78 PackageManager.DONT_KILL_APP);
79 sEnabledComponents.add(newEnabledComponent);
80 }
82 return null; 81 return null;
83 } 82 }
84 83
85 @Override 84 @Override
86 protected void onPostExecute(Void result) { 85 protected void onPostExecute(Void result) {
87 if (sStateChangeTask == this) { 86 if (sStateChangeTask == this) {
88 sStateChangeTask = null; 87 sStateChangeTask = null;
89 } else { 88 } else {
90 waitForPendingStateChangeTask(); 89 waitForPendingStateChangeTask();
91 } 90 }
92 callback.run(); 91 callback.run();
93 } 92 }
94 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 93 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
95 } else { 94 } else {
96 callback.run(); 95 callback.run();
97 } 96 }
98 } 97 }
99 98
100 private static void unregisterActivity(final Activity activity) { 99 /**
100 * Handles when the triggering activity has finished the sharing operation. If all
101 * pending shares have been complete then it will disable all enabled compon ents.
102 * @param triggeringActivity The activity that is triggering the share actio n.
103 */
104 public static void handleShareFinish(final Activity triggeringActivity) {
101 ThreadUtils.assertOnUiThread(); 105 ThreadUtils.assertOnUiThread();
102 106
103 sPendingShareActivities.remove(activity); 107 sPendingShareActivities.remove(triggeringActivity);
104 if (!sPendingShareActivities.isEmpty()) return; 108 if (!sPendingShareActivities.isEmpty()) return;
105 ApplicationStatus.unregisterActivityStateListener(sStateListener); 109 ApplicationStatus.unregisterActivityStateListener(sStateListener);
106 110
107 waitForPendingStateChangeTask(); 111 waitForPendingStateChangeTask();
108 sStateChangeTask = new AsyncTask<Void, Void, Void>() { 112 sStateChangeTask = new AsyncTask<Void, Void, Void>() {
109 @Override 113 @Override
110 protected Void doInBackground(Void... params) { 114 protected Void doInBackground(Void... params) {
111 if (!sPendingShareActivities.isEmpty()) return null; 115 if (!sPendingShareActivities.isEmpty()) return null;
112 116 for (int i = 0; i < sEnabledComponents.size(); i++) {
113 activity.getPackageManager().setComponentEnabledSetting( 117 triggeringActivity.getPackageManager().setComponentEnabledSe tting(
114 new ComponentName(activity, PrintShareActivity.class), 118 sEnabledComponents.get(i),
115 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 119 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
116 PackageManager.DONT_KILL_APP); 120 PackageManager.DONT_KILL_APP);
121 }
117 return null; 122 return null;
118 } 123 }
119 124
120 @Override 125 @Override
121 protected void onPostExecute(Void result) { 126 protected void onPostExecute(Void result) {
122 if (sStateChangeTask == this) sStateChangeTask = null; 127 if (sStateChangeTask == this) sStateChangeTask = null;
123 } 128 }
124 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 129 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
125 } 130 }
126 131
127 /** 132 /**
128 * Waits for any pending state change operations to be completed. 133 * Waits for any pending state change operations to be completed.
129 * 134 *
130 * This will avoid timing issues described here: crbug.com/649453. 135 * This will avoid timing issues described here: crbug.com/649453.
131 */ 136 */
132 private static void waitForPendingStateChangeTask() { 137 private static void waitForPendingStateChangeTask() {
133 ThreadUtils.assertOnUiThread(); 138 ThreadUtils.assertOnUiThread();
134 139
135 if (sStateChangeTask == null) return; 140 if (sStateChangeTask == null) return;
136 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 141 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
137 try { 142 try {
138 sStateChangeTask.get(); 143 sStateChangeTask.get();
139 sStateChangeTask = null; 144 sStateChangeTask = null;
140 } catch (InterruptedException | ExecutionException e) { 145 } catch (InterruptedException | ExecutionException e) {
141 Log.e(TAG, "Print state change task did not complete as expected"); 146 Log.e(TAG, "State change task did not complete as expected");
142 } finally { 147 } finally {
143 StrictMode.setThreadPolicy(oldPolicy); 148 StrictMode.setThreadPolicy(oldPolicy);
144 } 149 }
145 } 150 }
146 151 }
147 @Override
148 protected void onCreate(Bundle savedInstanceState) {
149 super.onCreate(savedInstanceState);
150
151 try {
152 Intent intent = getIntent();
153 if (intent == null) return;
154 if (!Intent.ACTION_SEND.equals(intent.getAction())) return;
155 if (!IntentUtils.safeHasExtra(getIntent(), ShareHelper.EXTRA_TASK_ID )) return;
156 handlePrintAction();
157 } finally {
158 finish();
159 }
160 }
161
162 private void handlePrintAction() {
163 int triggeringTaskId =
164 IntentUtils.safeGetIntExtra(getIntent(), ShareHelper.EXTRA_TASK_ ID, 0);
165 List<WeakReference<Activity>> activities = ApplicationStatus.getRunningA ctivities();
166 ChromeActivity triggeringActivity = null;
167 for (int i = 0; i < activities.size(); i++) {
168 Activity activity = activities.get(i).get();
169 if (activity == null) continue;
170
171 // Since the share intent is triggered without NEW_TASK or NEW_DOCUM ENT, the task ID
172 // of this activity will match that of the triggering activity.
173 if (activity.getTaskId() == triggeringTaskId
174 && activity instanceof ChromeActivity) {
175 triggeringActivity = (ChromeActivity) activity;
176 break;
177 }
178 }
179 if (triggeringActivity == null) return;
180 unregisterActivity(triggeringActivity);
181 triggeringActivity.onMenuOrKeyboardAction(R.id.print_id, true);
182 }
183
184 }
OLDNEW
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java ('k') | chrome/android/java_sources.gni » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698