Chromium Code Reviews| 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 |