| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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.printing; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.content.ComponentName; | |
| 9 import android.content.Intent; | 8 import android.content.Intent; |
| 10 import android.content.pm.PackageManager; | |
| 11 import android.os.AsyncTask; | |
| 12 import android.os.Bundle; | 9 import android.os.Bundle; |
| 13 import android.os.StrictMode; | |
| 14 import android.support.v7.app.AppCompatActivity; | 10 import android.support.v7.app.AppCompatActivity; |
| 15 | 11 |
| 16 import org.chromium.base.ActivityState; | |
| 17 import org.chromium.base.ApplicationStatus; | 12 import org.chromium.base.ApplicationStatus; |
| 18 import org.chromium.base.ApplicationStatus.ActivityStateListener; | |
| 19 import org.chromium.base.Log; | |
| 20 import org.chromium.base.ThreadUtils; | |
| 21 import org.chromium.chrome.R; | 13 import org.chromium.chrome.R; |
| 22 import org.chromium.chrome.browser.ChromeActivity; | 14 import org.chromium.chrome.browser.ChromeActivity; |
| 23 import org.chromium.chrome.browser.share.ShareHelper; | 15 import org.chromium.chrome.browser.share.ShareHelper; |
| 24 import org.chromium.chrome.browser.util.IntentUtils; | 16 import org.chromium.chrome.browser.util.IntentUtils; |
| 25 | 17 |
| 26 import java.lang.ref.WeakReference; | 18 import java.lang.ref.WeakReference; |
| 27 import java.util.Collections; | |
| 28 import java.util.HashSet; | |
| 29 import java.util.List; | 19 import java.util.List; |
| 30 import java.util.Set; | |
| 31 import java.util.concurrent.ExecutionException; | |
| 32 | 20 |
| 33 /** | 21 /** |
| 34 * A simple activity that allows Chrome to expose print as an option in the shar
e menu. | 22 * A simple activity that allows Chrome to expose print as an option in the shar
e menu. |
| 35 */ | 23 */ |
| 36 public class PrintShareActivity extends AppCompatActivity { | 24 public class PrintShareActivity extends AppCompatActivity { |
| 37 | 25 |
| 38 private static final String TAG = "cr_printing"; | 26 private static final String TAG = "cr_printing"; |
| 39 | 27 |
| 40 private static Set<Activity> sPendingShareActivities = | |
| 41 Collections.synchronizedSet(new HashSet<Activity>()); | |
| 42 private static ActivityStateListener sStateListener; | |
| 43 private static AsyncTask<Void, Void, Void> sStateChangeTask; | |
| 44 | |
| 45 /** | |
| 46 * Enable the print sharing option. | |
| 47 * | |
| 48 * @param activity The activity that will be triggering the share action. T
he activitiy's | |
| 49 * state will be tracked to disable the print option when th
e share operation | |
| 50 * has been completed. | |
| 51 * @param callback The callback to be triggered after the print option has b
een enabled. This | |
| 52 * may or may not be synchronous depending on whether this w
ill require | |
| 53 * interacting with the Android framework. | |
| 54 */ | |
| 55 public static void enablePrintShareOption(final Activity activity, final Run
nable callback) { | |
| 56 ThreadUtils.assertOnUiThread(); | |
| 57 | |
| 58 if (sStateListener == null) { | |
| 59 sStateListener = new ActivityStateListener() { | |
| 60 @Override | |
| 61 public void onActivityStateChange(Activity activity, int newStat
e) { | |
| 62 if (newState == ActivityState.PAUSED) return; | |
| 63 unregisterActivity(activity); | |
| 64 } | |
| 65 }; | |
| 66 } | |
| 67 ApplicationStatus.registerStateListenerForAllActivities(sStateListener); | |
| 68 boolean wasEmpty = sPendingShareActivities.isEmpty(); | |
| 69 sPendingShareActivities.add(activity); | |
| 70 | |
| 71 waitForPendingStateChangeTask(); | |
| 72 if (wasEmpty) { | |
| 73 sStateChangeTask = new AsyncTask<Void, Void, Void>() { | |
| 74 @Override | |
| 75 protected Void doInBackground(Void... params) { | |
| 76 if (sPendingShareActivities.isEmpty()) return null; | |
| 77 | |
| 78 activity.getPackageManager().setComponentEnabledSetting( | |
| 79 new ComponentName(activity, PrintShareActivity.class
), | |
| 80 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, | |
| 81 PackageManager.DONT_KILL_APP); | |
| 82 return null; | |
| 83 } | |
| 84 | |
| 85 @Override | |
| 86 protected void onPostExecute(Void result) { | |
| 87 if (sStateChangeTask == this) { | |
| 88 sStateChangeTask = null; | |
| 89 } else { | |
| 90 waitForPendingStateChangeTask(); | |
| 91 } | |
| 92 callback.run(); | |
| 93 } | |
| 94 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | |
| 95 } else { | |
| 96 callback.run(); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 private static void unregisterActivity(final Activity activity) { | |
| 101 ThreadUtils.assertOnUiThread(); | |
| 102 | |
| 103 sPendingShareActivities.remove(activity); | |
| 104 if (!sPendingShareActivities.isEmpty()) return; | |
| 105 ApplicationStatus.unregisterActivityStateListener(sStateListener); | |
| 106 | |
| 107 waitForPendingStateChangeTask(); | |
| 108 sStateChangeTask = new AsyncTask<Void, Void, Void>() { | |
| 109 @Override | |
| 110 protected Void doInBackground(Void... params) { | |
| 111 if (!sPendingShareActivities.isEmpty()) return null; | |
| 112 | |
| 113 activity.getPackageManager().setComponentEnabledSetting( | |
| 114 new ComponentName(activity, PrintShareActivity.class), | |
| 115 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, | |
| 116 PackageManager.DONT_KILL_APP); | |
| 117 return null; | |
| 118 } | |
| 119 | |
| 120 @Override | |
| 121 protected void onPostExecute(Void result) { | |
| 122 if (sStateChangeTask == this) sStateChangeTask = null; | |
| 123 } | |
| 124 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | |
| 125 } | |
| 126 | |
| 127 /** | |
| 128 * Waits for any pending state change operations to be completed. | |
| 129 * | |
| 130 * This will avoid timing issues described here: crbug.com/649453. | |
| 131 */ | |
| 132 private static void waitForPendingStateChangeTask() { | |
| 133 ThreadUtils.assertOnUiThread(); | |
| 134 | |
| 135 if (sStateChangeTask == null) return; | |
| 136 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); | |
| 137 try { | |
| 138 sStateChangeTask.get(); | |
| 139 sStateChangeTask = null; | |
| 140 } catch (InterruptedException | ExecutionException e) { | |
| 141 Log.e(TAG, "Print state change task did not complete as expected"); | |
| 142 } finally { | |
| 143 StrictMode.setThreadPolicy(oldPolicy); | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 @Override | 28 @Override |
| 148 protected void onCreate(Bundle savedInstanceState) { | 29 protected void onCreate(Bundle savedInstanceState) { |
| 149 super.onCreate(savedInstanceState); | 30 super.onCreate(savedInstanceState); |
| 150 | 31 |
| 151 try { | 32 try { |
| 152 Intent intent = getIntent(); | 33 Intent intent = getIntent(); |
| 153 if (intent == null) return; | 34 if (intent == null) return; |
| 154 if (!Intent.ACTION_SEND.equals(intent.getAction())) return; | 35 if (!Intent.ACTION_SEND.equals(intent.getAction())) return; |
| 155 if (!IntentUtils.safeHasExtra(getIntent(), ShareHelper.EXTRA_TASK_ID
)) return; | 36 if (!IntentUtils.safeHasExtra(getIntent(), ShareHelper.EXTRA_TASK_ID
)) return; |
| 156 handlePrintAction(); | 37 handlePrintAction(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 170 | 51 |
| 171 // Since the share intent is triggered without NEW_TASK or NEW_DOCUM
ENT, the task ID | 52 // 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. | 53 // of this activity will match that of the triggering activity. |
| 173 if (activity.getTaskId() == triggeringTaskId | 54 if (activity.getTaskId() == triggeringTaskId |
| 174 && activity instanceof ChromeActivity) { | 55 && activity instanceof ChromeActivity) { |
| 175 triggeringActivity = (ChromeActivity) activity; | 56 triggeringActivity = (ChromeActivity) activity; |
| 176 break; | 57 break; |
| 177 } | 58 } |
| 178 } | 59 } |
| 179 if (triggeringActivity == null) return; | 60 if (triggeringActivity == null) return; |
| 180 unregisterActivity(triggeringActivity); | 61 ShareHelper.unregisterActivity(triggeringActivity, |
| 62 ChromeActivity.getAdditionalShareOptionsList(null)); |
| 181 triggeringActivity.onMenuOrKeyboardAction(R.id.print_id, true); | 63 triggeringActivity.onMenuOrKeyboardAction(R.id.print_id, true); |
| 182 } | 64 } |
| 183 | |
| 184 } | 65 } |
| OLD | NEW |