OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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.multiwindow; | 5 package org.chromium.chrome.browser.multiwindow; |
6 | 6 |
7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
8 import android.app.Activity; | 8 import android.app.Activity; |
9 import android.app.ActivityManager; | 9 import android.app.ActivityManager; |
10 import android.app.ActivityManager.AppTask; | 10 import android.app.ActivityManager.AppTask; |
11 import android.content.Context; | 11 import android.content.Context; |
12 import android.content.Intent; | 12 import android.content.Intent; |
13 import android.os.Build; | 13 import android.os.Build; |
14 import android.provider.Browser; | 14 import android.provider.Browser; |
15 import android.text.TextUtils; | 15 import android.text.TextUtils; |
16 | 16 |
17 import org.chromium.base.ActivityState; | 17 import org.chromium.base.ActivityState; |
18 import org.chromium.base.ApplicationStatus; | 18 import org.chromium.base.ApplicationStatus; |
19 import org.chromium.base.ApplicationStatus.ActivityStateListener; | 19 import org.chromium.base.ApplicationStatus.ActivityStateListener; |
20 import org.chromium.base.VisibleForTesting; | 20 import org.chromium.base.VisibleForTesting; |
21 import org.chromium.chrome.browser.AppHooks; | 21 import org.chromium.chrome.browser.AppHooks; |
22 import org.chromium.chrome.browser.ChromeActivity; | |
22 import org.chromium.chrome.browser.ChromeTabbedActivity; | 23 import org.chromium.chrome.browser.ChromeTabbedActivity; |
23 import org.chromium.chrome.browser.ChromeTabbedActivity2; | 24 import org.chromium.chrome.browser.ChromeTabbedActivity2; |
24 import org.chromium.chrome.browser.IntentHandler; | 25 import org.chromium.chrome.browser.IntentHandler; |
25 import org.chromium.chrome.browser.document.ChromeLauncherActivity; | 26 import org.chromium.chrome.browser.document.ChromeLauncherActivity; |
27 import org.chromium.chrome.browser.tab.Tab; | |
26 import org.chromium.chrome.browser.util.IntentUtils; | 28 import org.chromium.chrome.browser.util.IntentUtils; |
27 | 29 |
30 import java.io.Serializable; | |
28 import java.lang.ref.WeakReference; | 31 import java.lang.ref.WeakReference; |
29 import java.lang.reflect.InvocationTargetException; | 32 import java.lang.reflect.InvocationTargetException; |
30 import java.lang.reflect.Method; | 33 import java.lang.reflect.Method; |
31 import java.util.List; | 34 import java.util.List; |
32 import java.util.concurrent.atomic.AtomicReference; | 35 import java.util.concurrent.atomic.AtomicReference; |
33 | 36 |
34 import javax.annotation.Nullable; | 37 import javax.annotation.Nullable; |
35 | 38 |
36 /** | 39 /** |
37 * Utilities for detecting multi-window/multi-instance support. | 40 * Utilities for detecting multi-window/multi-instance support. |
38 * | 41 * |
39 * Thread-safe: This class may be accessed from any thread. | 42 * Thread-safe: This class may be accessed from any thread. |
40 */ | 43 */ |
41 public class MultiWindowUtils implements ActivityStateListener { | 44 public class MultiWindowUtils implements ActivityStateListener { |
42 | 45 |
43 // TODO(twellington): replace this with Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT once we're building | 46 // TODO(twellington): replace this with Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT once we're building |
44 // against N. | 47 // against N. |
45 public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000; | 48 public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000; |
49 public static final String EXTRA_FROM_ACTIVITY_INTENT = | |
50 "org.chromium.chrome.browser.multiwindow.FromActivity"; | |
Theresa
2017/04/12 22:29:11
Rather than introducing a new intent flag, I think
PEConn
2017/04/26 17:24:37
Done.
| |
46 | 51 |
47 private static AtomicReference<MultiWindowUtils> sInstance = | 52 private static AtomicReference<MultiWindowUtils> sInstance = new AtomicRefer ence<>(); |
48 new AtomicReference<MultiWindowUtils>(); | |
49 | 53 |
50 // Used to keep track of whether ChromeTabbedActivity2 is running. A tri-sta te Boolean is | 54 // Used to keep track of whether ChromeTabbedActivity2 is running. A tri-sta te Boolean is |
51 // used in case both activities die in the background and MultiWindowUtils i s recreated. | 55 // used in case both activities die in the background and MultiWindowUtils i s recreated. |
52 private Boolean mTabbedActivity2TaskRunning; | 56 private Boolean mTabbedActivity2TaskRunning; |
53 private WeakReference<ChromeTabbedActivity> mLastResumedTabbedActivity; | 57 private WeakReference<ChromeTabbedActivity> mLastResumedTabbedActivity; |
54 private boolean mIsInMultiWindowModeForTesting; | 58 private boolean mIsInMultiWindowModeForTesting; |
55 | 59 |
56 /** | 60 /** |
57 * Returns the singleton instance of MultiWindowUtils, creating it if needed . | 61 * Returns the singleton instance of MultiWindowUtils, creating it if needed . |
58 */ | 62 */ |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 | 144 |
141 // Let Chrome know that this intent is from Chrome, so that it does not close the app when | 145 // Let Chrome know that this intent is from Chrome, so that it does not close the app when |
142 // the user presses 'back' button. | 146 // the user presses 'back' button. |
143 intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()) ; | 147 intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()) ; |
144 intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); | 148 intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); |
145 } | 149 } |
146 | 150 |
147 @Override | 151 @Override |
148 public void onActivityStateChange(Activity activity, int newState) { | 152 public void onActivityStateChange(Activity activity, int newState) { |
149 if (newState == ActivityState.RESUMED && activity instanceof ChromeTabbe dActivity) { | 153 if (newState == ActivityState.RESUMED && activity instanceof ChromeTabbe dActivity) { |
150 mLastResumedTabbedActivity = | 154 mLastResumedTabbedActivity = new WeakReference<>((ChromeTabbedActivi ty) activity); |
151 new WeakReference<ChromeTabbedActivity>((ChromeTabbedActivit y) activity); | |
152 } | 155 } |
153 } | 156 } |
154 | 157 |
155 /** | 158 /** |
156 * Determines the correct ChromeTabbedActivity class to use for an incoming intent. | 159 * Determines the correct ChromeTabbedActivity class to use for an incoming intent. |
157 * @param intent The incoming intent that is starting ChromeTabbedActivity. | 160 * @param intent The incoming intent that is starting ChromeTabbedActivity. |
158 * @param context The current Context, used to retrieve the ActivityManager system service. | 161 * @param context The current Context, used to retrieve the ActivityManager system service. |
159 * @return The ChromeTabbedActivity to use for the incoming intent. | 162 * @return The ChromeTabbedActivity to use for the incoming intent. |
160 */ | 163 */ |
161 public Class<? extends ChromeTabbedActivity> getTabbedActivityForIntent( | 164 public Class<? extends ChromeTabbedActivity> getTabbedActivityForIntent( |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 */ | 271 */ |
269 public static boolean isActivityVisible(Activity activity) { | 272 public static boolean isActivityVisible(Activity activity) { |
270 if (activity == null) return false; | 273 if (activity == null) return false; |
271 int activityState = ApplicationStatus.getStateForActivity(activity); | 274 int activityState = ApplicationStatus.getStateForActivity(activity); |
272 // In Android N multi-window mode, only one activity is resumed at a tim e. The other | 275 // In Android N multi-window mode, only one activity is resumed at a tim e. The other |
273 // activity visible on the screen will be in the paused state. Activitie s not visible on | 276 // activity visible on the screen will be in the paused state. Activitie s not visible on |
274 // the screen will be stopped or destroyed. | 277 // the screen will be stopped or destroyed. |
275 return activityState == ActivityState.RESUMED || activityState == Activi tyState.PAUSED; | 278 return activityState == ActivityState.RESUMED || activityState == Activi tyState.PAUSED; |
276 } | 279 } |
277 | 280 |
281 /** | |
282 * Moves a Tab to the other MultiWindow window. | |
283 * @param activity An {@link Activity} to use for context. | |
284 * @param tab The {@link Tab} to move. | |
285 */ | |
286 public static void moveTabToOtherWindow(Activity activity, Tab tab) { | |
287 moveTabToActivity( | |
288 activity, tab, getInstance().getOpenInOtherWindowActivity(activi ty), null); | |
289 } | |
290 | |
291 /** | |
292 * Moves a Tab to a specific Activity. | |
293 * @param activity An {@link Activity} for context. | |
294 * @param tab The {@link Tab} to move. | |
295 * @param targetActivity The class of the Activity to move the Tab to. | |
296 * @param finalizeCallback A callback that will be called after the tab is a ttached to the new | |
297 * host activity}. | |
298 */ | |
299 public static void moveTabToActivity(Activity activity, Tab tab, | |
300 Class<? extends Activity> targetActivity, @Nullable Runnable finaliz eCallback) { | |
301 if (targetActivity == null) return; | |
302 | |
303 Intent intent = new Intent(activity, targetActivity); | |
304 intent.putExtra(EXTRA_FROM_ACTIVITY_INTENT, tab.getActivity().getClass() ); | |
305 | |
306 MultiWindowUtils.setOpenInOtherWindowIntentExtras(intent, activity, targ etActivity); | |
307 MultiWindowUtils.onMultiInstanceModeStarted(); | |
Theresa
2017/04/12 22:29:11
"Multi-instance" mode has historically referred to
PEConn
2017/04/26 17:24:37
Acknowledged.
| |
308 tab.detachAndStartReparenting(intent, null, finalizeCallback); | |
309 } | |
310 | |
311 /** | |
312 * Extracts the class of the {@link Activity} that sent a {@link Tab} to the given Activity. | |
313 * May be null. | |
314 */ | |
315 @SuppressWarnings("unchecked") | |
316 public static Class<? extends ChromeActivity> getSenderActivity(Activity act ivity) { | |
Theresa
2017/04/12 22:29:11
Typically we use IntentUtils#safeGet*() to extract
PEConn
2017/04/26 17:24:37
Done.
| |
317 Serializable extra = activity.getIntent().getSerializableExtra(EXTRA_FRO M_ACTIVITY_INTENT); | |
318 if (extra == null) return null; | |
319 | |
320 assert extra instanceof Class; | |
321 Class<?> clazz = (Class<?>) extra; | |
322 | |
323 assert ChromeActivity.class.isAssignableFrom(clazz); | |
324 return (Class<? extends ChromeActivity>) clazz; | |
325 } | |
326 | |
278 @VisibleForTesting | 327 @VisibleForTesting |
279 public Boolean getTabbedActivity2TaskRunning() { | 328 public Boolean getTabbedActivity2TaskRunning() { |
280 return mTabbedActivity2TaskRunning; | 329 return mTabbedActivity2TaskRunning; |
281 } | 330 } |
282 | 331 |
283 /** | 332 /** |
284 * @param activity The {@link Activity} to check. | 333 * @param activity The {@link Activity} to check. |
285 * @return Whether or not {@code activity} is currently in pre-N Samsung mul ti-window mode. | 334 * @return Whether or not {@code activity} is currently in pre-N Samsung mul ti-window mode. |
286 */ | 335 */ |
287 public boolean isLegacyMultiWindow(Activity activity) { | 336 public boolean isLegacyMultiWindow(Activity activity) { |
(...skipping 20 matching lines...) Expand all Loading... | |
308 if (isLegacyMultiWindow(activity)) { | 357 if (isLegacyMultiWindow(activity)) { |
309 if (TextUtils.equals(ChromeTabbedActivity.class.getName(), | 358 if (TextUtils.equals(ChromeTabbedActivity.class.getName(), |
310 intent.getComponent().getClassName())) { | 359 intent.getComponent().getClassName())) { |
311 intent.setClassName(activity, MultiInstanceChromeTabbedActivity. class.getName()); | 360 intent.setClassName(activity, MultiInstanceChromeTabbedActivity. class.getName()); |
312 } | 361 } |
313 intent.setFlags(intent.getFlags() | 362 intent.setFlags(intent.getFlags() |
314 & ~(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW _DOCUMENT)); | 363 & ~(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW _DOCUMENT)); |
315 } | 364 } |
316 } | 365 } |
317 } | 366 } |
OLD | NEW |