RecentsImpl.java revision 5b4e0d2b11b2b3579bac36fde5ac3805346618cc
1190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/* 2190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Copyright (C) 2015 The Android Open Source Project 3190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * 4190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Licensed under the Apache License, Version 2.0 (the "License"); 5190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * you may not use this file except in compliance with the License. 6190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * You may obtain a copy of the License at 7190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * 8190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * http://www.apache.org/licenses/LICENSE-2.0 9190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * 10190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Unless required by applicable law or agreed to in writing, software 11190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * distributed under the License is distributed on an "AS IS" BASIS, 12190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * See the License for the specific language governing permissions and 14190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * limitations under the License. 15190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 16190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 17190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonpackage com.android.systemui.recents; 18190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 19190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityManager; 20190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityOptions; 21190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ITaskStackListener; 22b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajanimport android.app.UiModeManager; 23d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport android.appwidget.AppWidgetProviderInfo; 24190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.ActivityNotFoundException; 25190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Context; 26190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Intent; 27b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajanimport android.content.res.Configuration; 28190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.res.Resources; 29190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Bitmap; 30190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Canvas; 31190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Rect; 323150e574e6e903a17193e0b90433d69c0e20ae4cWinsonimport android.graphics.RectF; 33190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.Handler; 34190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.SystemClock; 35190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.UserHandle; 361b58561f66a9453754b1b419296899fdc08b4c93Winsonimport android.util.Log; 37190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.util.MutableBoolean; 38d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynskiimport android.view.AppTransitionAnimationSpec; 39190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.LayoutInflater; 40190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.View; 41b61e654b9a46e79827355104760a3ac5228380bcWinsonimport android.view.ViewConfiguration; 42c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 43190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.internal.logging.MetricsLogger; 44190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.Prefs; 45190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.R; 46190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.SystemUIApplication; 47412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.EventBus; 4811cc01df271fce5ec3eb05a7281032d1271cc782Jorim Jaggiimport com.android.systemui.recents.events.activity.DockingTopTaskEvent; 491b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; 50412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.HideRecentsEvent; 510d14d4da91c3d8b1221269712d5abf43a7cf9f31Winsonimport com.android.systemui.recents.events.activity.IterateRecentsEvent; 52b61e654b9a46e79827355104760a3ac5228380bcWinsonimport com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent; 53cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggiimport com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; 54412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.ToggleRecentsEvent; 55190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 56190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.ScreenPinningRequestEvent; 57dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; 58dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEvent; 596b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinsonimport com.android.systemui.recents.misc.DozeTrigger; 60ab84fc56114c0963c6f701de9725f5413ab76da9Winsonimport com.android.systemui.recents.misc.ForegroundThread; 61190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.misc.SystemServicesProxy; 62190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoadPlan; 63190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoader; 64190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.Task; 65190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskGrouping; 66190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskStack; 6736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winsonimport com.android.systemui.recents.views.TaskStackLayoutAlgorithm; 681b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.views.TaskStackView; 69190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewHeader; 70190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewTransform; 71d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport com.android.systemui.statusbar.BaseStatusBar; 72cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggiimport com.android.systemui.statusbar.phone.NavigationBarGestureHelper; 73190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.statusbar.phone.PhoneStatusBar; 74190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 75190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport java.util.ArrayList; 76190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 771b58561f66a9453754b1b419296899fdc08b4c93Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 781b58561f66a9453754b1b419296899fdc08b4c93Winson 79190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/** 80190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of the Recents component for the current user. For secondary users, this can 81190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * be called remotely from the system user. 82190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 83cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggipublic class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener { 84190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 85190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private final static String TAG = "RecentsImpl"; 86b61e654b9a46e79827355104760a3ac5228380bcWinson 876b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The minimum amount of time between each recents button press that we will handle 886b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson private final static int MIN_TOGGLE_DELAY_MS = 350; 89b61e654b9a46e79827355104760a3ac5228380bcWinson 906b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The duration within which the user releasing the alt tab (from when they pressed alt tab) 916b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // that the fast alt-tab animation will run. If the user's alt-tab takes longer than this 926b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // duration, then we will toggle recents after this duration. 936b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson private final static int FAST_ALT_TAB_DELAY_MS = 225; 94190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 95190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public final static String RECENTS_PACKAGE = "com.android.systemui"; 96190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity"; 97b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan public final static String RECENTS_TV_ACTIVITY = "com.android.systemui.recents.tv.RecentsTvActivity"; 98190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 99b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan //Used to store tv or non-tv activty for use in creating intents. 100b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan private final String mRecentsIntentActivityName; 101190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 102190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of ITaskStackListener, that allows us to listen for changes to the system 103190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * task stacks and update recents accordingly. 104190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 105190fe3bf88388fcb109af64571e3baa0d01f1c37Winson class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable { 106190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Handler mHandler; 107190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 108190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public TaskStackListenerImpl(Handler handler) { 109190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler = handler; 110190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 111190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 112190fe3bf88388fcb109af64571e3baa0d01f1c37Winson @Override 113190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onTaskStackChanged() { 114190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Debounce any task stack changes 115190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler.removeCallbacks(this); 116190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler.post(this); 117190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 118190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 11903ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale @Override 12003ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale public void onActivityPinned() { 12103ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale } 12203ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale 123cc25a8a24ea85409f440c052fdf36dc304cd7111Wale Ogunwale @Override 124cc25a8a24ea85409f440c052fdf36dc304cd7111Wale Ogunwale public void onPinnedActivityRestartAttempt() { 125cc25a8a24ea85409f440c052fdf36dc304cd7111Wale Ogunwale } 126cc25a8a24ea85409f440c052fdf36dc304cd7111Wale Ogunwale 127480dca0d1b08f8895f66f857e9bd341033fab2d9Wale Ogunwale @Override 128480dca0d1b08f8895f66f857e9bd341033fab2d9Wale Ogunwale public void onPinnedStackAnimationEnded() { 129480dca0d1b08f8895f66f857e9bd341033fab2d9Wale Ogunwale } 130480dca0d1b08f8895f66f857e9bd341033fab2d9Wale Ogunwale 131190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** Preloads the next task */ 132190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void run() { 133a0fdeec66caa4d70786c7f6f31f79a24eef9da10Jorim Jaggi RecentsConfiguration config = Recents.getConfiguration(); 134190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) { 135e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 136e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 137190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask(); 138190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 139190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Load the next task only if we aren't svelte 140190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 14165c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 142190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 143190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // This callback is made when a new activity is launched and the old one is paused 144190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // so ignore the current activity and try and preload the thumbnail for the 145190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // previous one. 146190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTaskInfo != null) { 147190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.runningTaskId = runningTaskInfo.id; 148190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 149190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTasks = 2; 150190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTaskThumbnails = 2; 151190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 152190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadPausedActivities = true; 153190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.loadTasks(mContext, plan, launchOpts); 154190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 155190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 156190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 157190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 158e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private static RecentsTaskLoadPlan sInstanceLoadPlan; 159190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 160190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Context mContext; 161190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Handler mHandler; 162190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStackListenerImpl mTaskStackListener; 163190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsAppWidgetHost mAppWidgetHost; 164190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean mBootCompleted; 165190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean mCanReuseTaskStackViews = true; 166dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean mDraggingInRecents; 167435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi boolean mReloadTasks; 168e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi boolean mLaunchedWhileDocking; 169190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 170190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Task launching 171190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mSearchBarBounds = new Rect(); 172190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mTaskStackBounds = new Rect(); 173190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mLastTaskViewBounds = new Rect(); 174190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskViewTransform mTmpTransform = new TaskViewTransform(); 175190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mStatusBarHeight; 176190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mNavBarHeight; 177190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mNavBarWidth; 178190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mTaskBarHeight; 179190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 180190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Header (for transition) 181190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskViewHeader mHeaderBar; 182190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final Object mHeaderBarLock = new Object(); 183190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStackView mDummyStackView; 184190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 185190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Variables to keep track of if we need to start recents after binding 186190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean mTriggeredFromAltTab; 187190fe3bf88388fcb109af64571e3baa0d01f1c37Winson long mLastToggleTime; 1886b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson DozeTrigger mFastAltTabTrigger = new DozeTrigger(FAST_ALT_TAB_DELAY_MS, new Runnable() { 1896b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson @Override 1906b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson public void run() { 1916b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // When this fires, then the user has not released alt-tab for at least 1926b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // FAST_ALT_TAB_DELAY_MS milliseconds 193435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi showRecents(mTriggeredFromAltTab, false /* draggingInRecents */, true /* animate */, 194435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi false /* reloadTasks */); 1956b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 1966b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson }); 197190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 198190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap mThumbnailTransitionBitmapCache; 199190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task mThumbnailTransitionBitmapCacheKey; 200190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 201190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public RecentsImpl(Context context) { 202190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext = context; 203190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler = new Handler(); 2041b58561f66a9453754b1b419296899fdc08b4c93Winson mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID); 205190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 206ab84fc56114c0963c6f701de9725f5413ab76da9Winson // Initialize the static foreground thread 207ab84fc56114c0963c6f701de9725f5413ab76da9Winson ForegroundThread.get(); 208ab84fc56114c0963c6f701de9725f5413ab76da9Winson 209190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Register the task stack listener 210190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTaskStackListener = new TaskStackListenerImpl(mHandler); 211e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 212e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.registerTaskStackListener(mTaskStackListener); 213190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 214190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Initialize the static configuration resources 215b94443d876d3c9575e88078d0e537bb385f79ca4Winson reloadHeaderBarLayout(); 216b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 217190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 218190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // When we start, preload the data associated with the previous recent tasks. 219190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // We can use a new plan since the caches will be the same. 220e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 221190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 22265c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 223190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 224296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung launchOpts.numVisibleTasks = loader.getIconCacheSize(); 225190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize(); 226190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 227190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.loadTasks(mContext, plan, launchOpts); 228b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan 229b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan //Manager used to determine if we are running on tv or not 230b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE); 231b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) { 232b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan mRecentsIntentActivityName = RECENTS_TV_ACTIVITY; 233b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan } else { 234b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan mRecentsIntentActivityName = RECENTS_ACTIVITY; 235b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan } 236190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 237190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 238190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onBootCompleted() { 239190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mBootCompleted = true; 240b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 241190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 242190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 243190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onConfigurationChanged() { 244b94443d876d3c9575e88078d0e537bb385f79ca4Winson reloadHeaderBarLayout(); 245b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 246190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Don't reuse task stack views if the configuration changes 247190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mCanReuseTaskStackViews = false; 24853ec42cb17693b2d631746e1e5d31021a3359163Winson Recents.getConfiguration().updateOnConfigurationChange(); 249190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 250190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 251190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 252190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * This is only called from the system user's Recents. Secondary users will instead proxy their 253190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * visibility change events through to the system user via 254190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}. 255190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 256190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onVisibilityChanged(Context context, boolean visible) { 257190fe3bf88388fcb109af64571e3baa0d01f1c37Winson SystemUIApplication app = (SystemUIApplication) context; 258190fe3bf88388fcb109af64571e3baa0d01f1c37Winson PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); 259190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (statusBar != null) { 260190fe3bf88388fcb109af64571e3baa0d01f1c37Winson statusBar.updateRecentsVisibility(visible); 261190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 262190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 263190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 264190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 265190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * This is only called from the system user's Recents. Secondary users will instead proxy their 266190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * visibility change events through to the system user via 267190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}. 268190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 269190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onStartScreenPinning(Context context) { 270190fe3bf88388fcb109af64571e3baa0d01f1c37Winson SystemUIApplication app = (SystemUIApplication) context; 271190fe3bf88388fcb109af64571e3baa0d01f1c37Winson PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); 272190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (statusBar != null) { 273190fe3bf88388fcb109af64571e3baa0d01f1c37Winson statusBar.showScreenPinningRequest(false); 274190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 275190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 276190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 277bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, 278e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi boolean animate, boolean launchedWhileDockingTask) { 279190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTriggeredFromAltTab = triggeredFromAltTab; 280dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDraggingInRecents = draggingInRecents; 281e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi mLaunchedWhileDocking = launchedWhileDockingTask; 2826b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (mFastAltTabTrigger.hasTriggered()) { 2836b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // We are calling this from the doze trigger, so just fall through to show Recents 2846b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.resetTrigger(); 2856b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } else if (mFastAltTabTrigger.isDozing()) { 2866b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // We are dozing but haven't yet triggered, ignore this if this is not another alt-tab, 2876b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // otherwise, this is an additional tab (alt-tab*), which means that we should trigger 2886b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // immediately (fall through and disable the pending trigger) 2896b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // TODO: This is tricky, we need to handle the tab key, but Recents has not yet started 2906b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // so we may actually additional signal to handle multiple quick tab cases. The 2916b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // severity of this is inversely proportional to the FAST_ALT_TAB_DELAY_MS 2926b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // duration though 2936b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (!triggeredFromAltTab) { 2946b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 2956b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 2966b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.stopDozing(); 2976b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } else { 2986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Otherwise, the doze trigger is not running, and if this is an alt tab, we should 2996b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // start the trigger and then wait for the hide (or for it to elapse) 3006b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (triggeredFromAltTab) { 3016b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.startDozing(); 3026b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 3036b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 3046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 305190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 306190fe3bf88388fcb109af64571e3baa0d01f1c37Winson try { 307190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Check if the top task is in the home stack, and start the recents activity 308e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 309e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 310190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean isTopTaskHome = new MutableBoolean(true); 311e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) { 312bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, isTopTaskHome.value, animate); 313190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 314190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } catch (ActivityNotFoundException e) { 3151b58561f66a9453754b1b419296899fdc08b4c93Winson Log.e(TAG, "Failed to launch RecentsActivity", e); 316190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 317190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 318190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 319190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 320190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (mBootCompleted) { 3216b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) { 3226b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The user has released alt-tab before the trigger has run, so just show the next 3236b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // task immediately 3246b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson showNextTask(); 3256b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 3266b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Cancel the fast alt-tab trigger 3276b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.stopDozing(); 3286b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.resetTrigger(); 3296b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 3306b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 3316b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 332190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Defer to the activity to handle hiding recents, if it handles it, then it must still 333190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // be visible 334e7f138c7f0a190c86cec10fb32fa106aacae4093Winson EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab, 335412e18058dc2cd5779d2451fce7fd74631f9e237Winson triggeredFromHomeKey)); 336190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 337190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 338190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 339190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void toggleRecents() { 3406b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Skip this toggle if we are already waiting to trigger recents via alt-tab 3416b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (mFastAltTabTrigger.isDozing()) { 3426b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 3436b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 3446b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 345dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDraggingInRecents = false; 346e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi mLaunchedWhileDocking = false; 347190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTriggeredFromAltTab = false; 348190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 349190fe3bf88388fcb109af64571e3baa0d01f1c37Winson try { 350b61e654b9a46e79827355104760a3ac5228380bcWinson ViewConfiguration viewConfig = ViewConfiguration.get(mContext); 351e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 352e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 353190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean isTopTaskHome = new MutableBoolean(true); 354b61e654b9a46e79827355104760a3ac5228380bcWinson long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime; 355b61e654b9a46e79827355104760a3ac5228380bcWinson 356e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { 3575da4347b41b105dc6c6c01bf2810af3ce3013229Winson RecentsConfiguration config = Recents.getConfiguration(); 3585da4347b41b105dc6c6c01bf2810af3ce3013229Winson RecentsActivityLaunchState launchState = config.getLaunchState(); 359ead5c0fc20e5c60a68cd017af0b8eacaf1167a1cWinson Chung if (!launchState.launchedWithAltTab) { 360b61e654b9a46e79827355104760a3ac5228380bcWinson // If the user taps quickly 361b61e654b9a46e79827355104760a3ac5228380bcWinson if (ViewConfiguration.getDoubleTapMinTime() < elapsedTime && 362b61e654b9a46e79827355104760a3ac5228380bcWinson elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { 363b61e654b9a46e79827355104760a3ac5228380bcWinson // Launch the next focused task 364b61e654b9a46e79827355104760a3ac5228380bcWinson EventBus.getDefault().post(new LaunchNextTaskRequestEvent()); 365b61e654b9a46e79827355104760a3ac5228380bcWinson } else { 366b61e654b9a46e79827355104760a3ac5228380bcWinson // Notify recents to move onto the next task 367b61e654b9a46e79827355104760a3ac5228380bcWinson EventBus.getDefault().post(new IterateRecentsEvent()); 368b61e654b9a46e79827355104760a3ac5228380bcWinson } 3690d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } else { 3700d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // If the user has toggled it too quickly, then just eat up the event here (it's 3710d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // better than showing a janky screenshot). 3720d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // NOTE: Ideally, the screenshot mechanism would take the window transform into 3730d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // account 374b61e654b9a46e79827355104760a3ac5228380bcWinson if (elapsedTime < MIN_TOGGLE_DELAY_MS) { 3750d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson return; 3760d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 3770d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson 3780d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson EventBus.getDefault().post(new ToggleRecentsEvent()); 3790d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson mLastToggleTime = SystemClock.elapsedRealtime(); 3800d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 381190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return; 382190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 3830d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // If the user has toggled it too quickly, then just eat up the event here (it's 3840d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // better than showing a janky screenshot). 3850d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // NOTE: Ideally, the screenshot mechanism would take the window transform into 3860d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // account 387b61e654b9a46e79827355104760a3ac5228380bcWinson if (elapsedTime < MIN_TOGGLE_DELAY_MS) { 3880d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson return; 3890d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 3900d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson 391190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Otherwise, start the recents activity 392bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */); 393d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson 394d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson // Only close the other system windows if we are actually showing recents 395d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS); 3960d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson mLastToggleTime = SystemClock.elapsedRealtime(); 397190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 398190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } catch (ActivityNotFoundException e) { 3991b58561f66a9453754b1b419296899fdc08b4c93Winson Log.e(TAG, "Failed to launch RecentsActivity", e); 400190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 401190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 402190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 403190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void preloadRecents() { 404190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Preload only the raw task list into a new load plan (which will be consumed by the 405190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // RecentsActivity) only if there is a task to animate to. 406e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 407e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 408190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean topTaskHome = new MutableBoolean(true); 409e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) { 4105b4e0d2b11b2b3579bac36fde5ac3805346618ccWinson RecentsTaskLoader loader = Recents.getTaskLoader(); 4115b4e0d2b11b2b3579bac36fde5ac3805346618ccWinson sInstanceLoadPlan = loader.createLoadPlan(mContext); 412190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan.preloadRawTasks(topTaskHome.value); 41365c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value); 414190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack = sInstanceLoadPlan.getTaskStack(); 4154b057c6787624b75613769a857ccdf51114bb7f2Winson if (stack.getTaskCount() > 0) { 416ab84fc56114c0963c6f701de9725f5413ab76da9Winson // We try and draw the thumbnail transition bitmap in parallel before 417ab84fc56114c0963c6f701de9725f5413ab76da9Winson // toggle/show recents is called 418190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView); 419190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 420190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 421190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 422190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 423190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void cancelPreloadingRecents() { 424190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Do nothing 425190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 426190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 427dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void onDraggingInRecents(float distanceFromTop) { 428dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop)); 429dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 430dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 431dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void onDraggingInRecentsEnded(float velocity) { 432dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity)); 433dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 434dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 4356b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson /** 4366b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson * Transitions to the next recent task in the stack. 4376b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson */ 4386b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson public void showNextTask() { 4396b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson SystemServicesProxy ssp = Recents.getSystemServices(); 4406b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson RecentsTaskLoader loader = Recents.getTaskLoader(); 4416b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 44265c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 4436b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson TaskStack focusedStack = plan.getTaskStack(); 4446b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4456b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there are no tasks in the focused stack 4464b057c6787624b75613769a857ccdf51114bb7f2Winson if (focusedStack == null || focusedStack.getTaskCount() == 0) return; 4476b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4486b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask(); 4496b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there is no running task 4506b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (runningTask == null) return; 4516b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4526b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Find the task in the recents list 453e86deb8adb022ba7721a1af1112d3a45e757095cWinson boolean isTopTaskHome = SystemServicesProxy.isHomeStack(runningTask.stackId); 454250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = focusedStack.getStackTasks(); 4556b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson Task toTask = null; 4566b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityOptions launchOpts = null; 4576b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson int taskCount = tasks.size(); 4586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson for (int i = taskCount - 1; i >= 1; i--) { 4596b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson Task task = tasks.get(i); 460e86deb8adb022ba7721a1af1112d3a45e757095cWinson if (isTopTaskHome) { 461e86deb8adb022ba7721a1af1112d3a45e757095cWinson toTask = tasks.get(i - 1); 462e86deb8adb022ba7721a1af1112d3a45e757095cWinson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 463e86deb8adb022ba7721a1af1112d3a45e757095cWinson R.anim.recents_launch_next_affiliated_task_target, 464e86deb8adb022ba7721a1af1112d3a45e757095cWinson R.anim.recents_fast_toggle_app_home_exit); 465e86deb8adb022ba7721a1af1112d3a45e757095cWinson break; 466e86deb8adb022ba7721a1af1112d3a45e757095cWinson } else if (task.key.id == runningTask.id) { 4676b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson toTask = tasks.get(i - 1); 4686b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 4696b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_target, 4706b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_source); 4716b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson break; 4726b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4736b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4746b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4756b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there is no next task 4766b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (toTask == null) { 4776b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ssp.startInPlaceAnimationOnFrontMostApplication( 4786b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityOptions.makeCustomInPlaceAnimation(mContext, 4796b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_bounce)); 4806b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 4816b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4826b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4836b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Launch the task 484296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts); 4856b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4866b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4876b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson /** 4886b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson * Transitions to the next affiliated task. 4896b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson */ 490190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showRelativeAffiliatedTask(boolean showNextTask) { 491e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 492e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 493190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 49465c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 495190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack focusedStack = plan.getTaskStack(); 496190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 497190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there are no tasks in the focused stack 4984b057c6787624b75613769a857ccdf51114bb7f2Winson if (focusedStack == null || focusedStack.getTaskCount() == 0) return; 499190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 500e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask(); 501190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there is no running task (can't determine affiliated tasks in this case) 502190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTask == null) return; 503190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if the running task is in the home stack (optimization) 5045510f6c1b9c20483e1507147eed7b24ac8bb6363Winson if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return; 505190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 506190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Find the task in the recents list 507250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = focusedStack.getStackTasks(); 508190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task toTask = null; 509190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions launchOpts = null; 510190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskCount = tasks.size(); 511190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int numAffiliatedTasks = 0; 512190fe3bf88388fcb109af64571e3baa0d01f1c37Winson for (int i = 0; i < taskCount; i++) { 513190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task task = tasks.get(i); 514190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (task.key.id == runningTask.id) { 515190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskGrouping group = task.group; 516190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task.TaskKey toTaskKey; 517190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (showNextTask) { 518190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTaskKey = group.getNextTaskInGroup(task); 519190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 520190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_target, 521190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_source); 522190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 523190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTaskKey = group.getPrevTaskInGroup(task); 524190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 525190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_target, 526190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_source); 527190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 528190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTaskKey != null) { 529190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTask = focusedStack.findTaskWithId(toTaskKey.id); 530190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 531190fe3bf88388fcb109af64571e3baa0d01f1c37Winson numAffiliatedTasks = group.getTaskCount(); 532190fe3bf88388fcb109af64571e3baa0d01f1c37Winson break; 533190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 534190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 535190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 536190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there is no next task 537190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTask == null) { 538190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (numAffiliatedTasks > 1) { 539190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (showNextTask) { 540e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.startInPlaceAnimationOnFrontMostApplication( 541190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions.makeCustomInPlaceAnimation(mContext, 542190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_bounce)); 543190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 544e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.startInPlaceAnimationOnFrontMostApplication( 545190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions.makeCustomInPlaceAnimation(mContext, 546190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_bounce)); 547190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 548190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 549190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return; 550190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 551190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 552190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of actually launched affiliated tasks 553190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1); 554190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 555190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Launch the task 556296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts); 557190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 558190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 559190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showNextAffiliatedTask() { 560190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of when the affiliated task is triggered 561190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_next", 1); 562190fe3bf88388fcb109af64571e3baa0d01f1c37Winson showRelativeAffiliatedTask(true); 563190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 564190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 565190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showPrevAffiliatedTask() { 566190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of when the affiliated task is triggered 567190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1); 568190fe3bf88388fcb109af64571e3baa0d01f1c37Winson showRelativeAffiliatedTask(false); 569190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 570190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 571cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi public void dockTopTask(int topTaskId, int dragMode, 572cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi int stackCreateMode, Rect initialBounds) { 57375b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi SystemServicesProxy ssp = Recents.getSystemServices(); 5749511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi 5759511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi // Make sure we inform DividerView before we actually start the activity so we can change 5769511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi // the resize mode already. 5779511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi EventBus.getDefault().send(new DockingTopTaskEvent(dragMode)); 578cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds); 579cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi showRecents(false /* triggeredFromAltTab */, 580cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */, 581cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi true /* reloadTasks*/); 58275b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi } 58375b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi 584190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 585190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Returns the preloaded load plan and invalidates it. 586190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 587190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public static RecentsTaskLoadPlan consumeInstanceLoadPlan() { 588190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = sInstanceLoadPlan; 589190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = null; 590190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return plan; 591190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 592190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 593190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 594b94443d876d3c9575e88078d0e537bb385f79ca4Winson * Reloads all the layouts for the header bar transition. 595b94443d876d3c9575e88078d0e537bb385f79ca4Winson */ 596b94443d876d3c9575e88078d0e537bb385f79ca4Winson private void reloadHeaderBarLayout() { 597b94443d876d3c9575e88078d0e537bb385f79ca4Winson Resources res = mContext.getResources(); 598b94443d876d3c9575e88078d0e537bb385f79ca4Winson LayoutInflater inflater = LayoutInflater.from(mContext); 599b94443d876d3c9575e88078d0e537bb385f79ca4Winson 600b94443d876d3c9575e88078d0e537bb385f79ca4Winson mStatusBarHeight = res.getDimensionPixelSize( 601b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.status_bar_height); 602b94443d876d3c9575e88078d0e537bb385f79ca4Winson mNavBarHeight = res.getDimensionPixelSize( 603b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.navigation_bar_height); 604b94443d876d3c9575e88078d0e537bb385f79ca4Winson mNavBarWidth = res.getDimensionPixelSize( 605b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.navigation_bar_width); 606b94443d876d3c9575e88078d0e537bb385f79ca4Winson mTaskBarHeight = res.getDimensionPixelSize( 607b94443d876d3c9575e88078d0e537bb385f79ca4Winson R.dimen.recents_task_bar_height); 608b94443d876d3c9575e88078d0e537bb385f79ca4Winson mDummyStackView = new TaskStackView(mContext, new TaskStack()); 609b94443d876d3c9575e88078d0e537bb385f79ca4Winson mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, 610b94443d876d3c9575e88078d0e537bb385f79ca4Winson null, false); 611b94443d876d3c9575e88078d0e537bb385f79ca4Winson } 612b94443d876d3c9575e88078d0e537bb385f79ca4Winson 613b94443d876d3c9575e88078d0e537bb385f79ca4Winson /** 614190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Prepares the header bar layout for the next transition, if the task view bounds has changed 615190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * since the last call, it will attempt to re-measure and layout the header bar to the new size. 616190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * 617190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one 618190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * is not already bound (can be expensive) 619f0d1c44a59a10707baa0cca8dd377302260710c1Winson * @param stack the stack to initialize the stack layout with 620190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 621b94443d876d3c9575e88078d0e537bb385f79ca4Winson private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, 622b94443d876d3c9575e88078d0e537bb385f79ca4Winson TaskStack stack) { 62353ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 624e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 625c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect systemInsets = new Rect(); 626c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi ssp.getStableInsets(systemInsets); 627e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Rect windowRect = ssp.getWindowRect(); 628c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi calculateWindowStableInsets(systemInsets, windowRect); 629c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi windowRect.offsetTo(0, 0); 630190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 631190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the configuration for the current state 632c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi config.update(systemInsets); 633190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 634d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) { 635190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Try and pre-emptively bind the search widget on startup to ensure that we 636190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // have the right thumbnail bounds to animate to. 637190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Note: We have to reload the widget id before we get the task stack bounds below 638e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) { 63953ec42cb17693b2d631746e1e5d31021a3359163Winson config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds); 640190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 641190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 64253ec42cb17693b2d631746e1e5d31021a3359163Winson config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right, 643190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mSearchBarBounds, mTaskStackBounds); 644190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 645190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Rebind the header bar and draw it for the transition 64636a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm(); 647190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect taskStackBounds = new Rect(mTaskStackBounds); 648190fe3bf88388fcb109af64571e3baa0d01f1c37Winson algo.setSystemInsets(systemInsets); 649f0d1c44a59a10707baa0cca8dd377302260710c1Winson if (stack != null) { 650f0d1c44a59a10707baa0cca8dd377302260710c1Winson algo.initialize(taskStackBounds, 651f0d1c44a59a10707baa0cca8dd377302260710c1Winson TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack)); 652f0d1c44a59a10707baa0cca8dd377302260710c1Winson } 653190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect taskViewBounds = algo.getUntransformedTaskViewBounds(); 654190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (!taskViewBounds.equals(mLastTaskViewBounds)) { 655190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mLastTaskViewBounds.set(taskViewBounds); 656190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 657190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskViewWidth = taskViewBounds.width(); 658190fe3bf88388fcb109af64571e3baa0d01f1c37Winson synchronized (mHeaderBarLock) { 659190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.measure( 660190fe3bf88388fcb109af64571e3baa0d01f1c37Winson View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY), 661190fe3bf88388fcb109af64571e3baa0d01f1c37Winson View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY)); 662190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight); 663190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 664190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 665190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 666190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 667190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 668c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi * Given the stable insets and the rect for our window, calculates the insets that affect our 669c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi * window. 670c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi */ 671c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi private void calculateWindowStableInsets(Rect inOutInsets, Rect windowRect) { 672c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect displayRect = Recents.getSystemServices().getDisplayRect(); 673c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi 674c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi // Display rect without insets - available app space 675c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect appRect = new Rect(displayRect); 676c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi appRect.inset(inOutInsets); 677c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi 678c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi // Our window intersected with available app space 679c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect windowRectWithInsets = new Rect(windowRect); 680c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi windowRectWithInsets.intersect(appRect); 681c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.left = windowRectWithInsets.left - windowRect.left; 682c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.top = windowRectWithInsets.top - windowRect.top; 683c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.right = windowRect.right - windowRectWithInsets.right; 684c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.bottom = windowRect.bottom - windowRectWithInsets.bottom; 685c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi } 686c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi 687c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi /** 688190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Preloads the icon of a task. 689190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 690190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void preloadIcon(ActivityManager.RunningTaskInfo task) { 691190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Ensure that we load the running task's icon 692190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 693190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.runningTaskId = task.id; 694190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.loadThumbnails = false; 695190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 696e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts); 697190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 698190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 699190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 700190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Caches the header thumbnail used for a window animation asynchronously into 701190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link #mThumbnailTransitionBitmapCache}. 702190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 703190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask, 704190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack, TaskStackView stackView) { 705190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preloadIcon(topTask); 706190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 707190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the header bar if necessary 708b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); 709190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 710190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the destination rect 711eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mDummyStackView.updateLayoutForStack(stack); 712190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final Task toTask = new Task(); 713190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, 71435a8b04140598a5b5c4865254b942adb6a830991Winson toTask); 7153fb67562c548662910160d5672b1b9558bd6571cWinson ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() { 716190fe3bf88388fcb109af64571e3baa0d01f1c37Winson @Override 717ab84fc56114c0963c6f701de9725f5413ab76da9Winson public void run() { 718ab84fc56114c0963c6f701de9725f5413ab76da9Winson final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform); 719ab84fc56114c0963c6f701de9725f5413ab76da9Winson mHandler.post(new Runnable() { 720ab84fc56114c0963c6f701de9725f5413ab76da9Winson @Override 721ab84fc56114c0963c6f701de9725f5413ab76da9Winson public void run() { 722ab84fc56114c0963c6f701de9725f5413ab76da9Winson mThumbnailTransitionBitmapCache = transitionBitmap; 723ab84fc56114c0963c6f701de9725f5413ab76da9Winson mThumbnailTransitionBitmapCacheKey = toTask; 724ab84fc56114c0963c6f701de9725f5413ab76da9Winson } 725ab84fc56114c0963c6f701de9725f5413ab76da9Winson }); 726190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 727ab84fc56114c0963c6f701de9725f5413ab76da9Winson }); 728190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 729190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 730190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 731190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for a unknown state->recents transition. 732190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 733190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getUnknownTransitionActivityOptions() { 734190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 735190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_unknown_enter, 736190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_unknown_exit, 7373fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 738190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 739190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 740190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 741190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for a home->recents transition. 742190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 743190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) { 744190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (fromSearchHome) { 745190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 746190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_search_launcher_enter, 747190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_search_launcher_exit, 7483fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 749190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 750190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 751190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_launcher_enter, 752190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_launcher_exit, 7533fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 754190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 755190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 756190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 757190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for an app->recents transition. 758190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 759190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getThumbnailTransitionActivityOptions( 760190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) { 761d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) { 762d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>(); 763d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski stackView.getScroller().setStackScrollToInitialState(); 764250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = stack.getStackTasks(); 765d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski for (int i = tasks.size() - 1; i >= 0; i--) { 766d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Task task = tasks.get(i); 767387aac6ad7bde21f2c2510cb8a2f3af3959721e0Winson if (task.isFreeformTask()) { 768c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi mTmpTransform = stackView.getStackAlgorithm() 769c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi .getStackTransformScreenCoordinates(task, 770c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi stackView.getScroller().getStackScroll(), mTmpTransform, null); 771d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Rect toTaskRect = new Rect(); 772d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski mTmpTransform.rect.round(toTaskRect); 773d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform); 774d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect)); 775d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 776d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 777d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()]; 778d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski specs.toArray(specsArray); 779d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, 7803fb67562c548662910160d5672b1b9558bd6571cWinson specsArray, mHandler, null, this); 781d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } else { 782d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski // Update the destination rect 783d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Task toTask = new Task(); 784d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, 78535a8b04140598a5b5c4865254b942adb6a830991Winson toTask); 786d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski RectF toTaskRect = toTransform.rect; 787d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform); 788d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski if (thumbnail != null) { 789d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, 790d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski thumbnail, (int) toTaskRect.left, (int) toTaskRect.top, 7913fb67562c548662910160d5672b1b9558bd6571cWinson (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null); 792d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 793d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski // If both the screenshot and thumbnail fails, then just fall back to the default transition 794d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return getUnknownTransitionActivityOptions(); 795d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 796d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 797190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 798d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask, 799d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski TaskViewTransform toTransform) { 800190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap thumbnail; 801190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (mThumbnailTransitionBitmapCacheKey != null 802190fe3bf88388fcb109af64571e3baa0d01f1c37Winson && mThumbnailTransitionBitmapCacheKey.key != null 803190fe3bf88388fcb109af64571e3baa0d01f1c37Winson && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) { 804190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = mThumbnailTransitionBitmapCache; 805190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mThumbnailTransitionBitmapCacheKey = null; 806190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mThumbnailTransitionBitmapCache = null; 807190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 808190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preloadIcon(topTask); 809190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform); 810190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 811d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return thumbnail; 812190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 813190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 814190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 815190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Returns the transition rect for the given task id. 816190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 817190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, 81835a8b04140598a5b5c4865254b942adb6a830991Winson TaskStackView stackView, Task runningTaskOut) { 819190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Find the running task in the TaskStack 82065c851e6e9e08656744b6f66d3da188e3283b17dWinson Task launchTask = stack.getLaunchTarget(); 82165c851e6e9e08656744b6f66d3da188e3283b17dWinson if (launchTask != null) { 82265c851e6e9e08656744b6f66d3da188e3283b17dWinson runningTaskOut.copyFrom(launchTask); 82365c851e6e9e08656744b6f66d3da188e3283b17dWinson } else { 824190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // If no task is specified or we can not find the task just use the front most one 82535a8b04140598a5b5c4865254b942adb6a830991Winson launchTask = stack.getStackFrontMostTask(true /* includeFreeform */); 82665c851e6e9e08656744b6f66d3da188e3283b17dWinson runningTaskOut.copyFrom(launchTask); 827190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 828190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 829190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Get the transform for the running task 830190fe3bf88388fcb109af64571e3baa0d01f1c37Winson stackView.getScroller().setStackScrollToInitialState(); 831c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask, 832190fe3bf88388fcb109af64571e3baa0d01f1c37Winson stackView.getScroller().getStackScroll(), mTmpTransform, null); 833190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return mTmpTransform; 834190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 835190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 836190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 837190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Draws the header of a task used for the window animation into a bitmap. 838190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 839190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) { 8408be1634a543022bd6ee0c1e974d3201d452981e8Winson SystemServicesProxy ssp = Recents.getSystemServices(); 841190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTransform != null && toTask.key != null) { 842190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap thumbnail; 843190fe3bf88388fcb109af64571e3baa0d01f1c37Winson synchronized (mHeaderBarLock) { 844509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung int toHeaderWidth = (int) toTransform.rect.width(); 845190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); 8468be1634a543022bd6ee0c1e974d3201d452981e8Winson boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode(); 847509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(), 848509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung (int) toTransform.rect.height()); 849190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, 850190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap.Config.ARGB_8888); 851c742f973b1e506732911c156c5869fd377afc5bfWinson if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { 852190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail.eraseColor(0xFFff0000); 853190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 854190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Canvas c = new Canvas(thumbnail); 855190fe3bf88388fcb109af64571e3baa0d01f1c37Winson c.scale(toTransform.scale, toTransform.scale); 8568be1634a543022bd6ee0c1e974d3201d452981e8Winson mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */, 8578be1634a543022bd6ee0c1e974d3201d452981e8Winson disabledInSafeMode); 858190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.draw(c); 859190fe3bf88388fcb109af64571e3baa0d01f1c37Winson c.setBitmap(null); 860190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 861190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 862190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return thumbnail.createAshmemBitmap(); 863190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 864190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return null; 865190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 866190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 867190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 868190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Shows the recents activity 869190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 870190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, 871bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi boolean isTopTaskHome, boolean animate) { 872e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 873190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 874e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we 875435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi // should always preload the tasks now. If we are dragging in recents, reload them as 876435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi // the stacks might have changed. 877e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi if (mLaunchedWhileDocking || mTriggeredFromAltTab ||sInstanceLoadPlan == null) { 878e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson // Create a new load plan if preloadRecents() was never triggered 879190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = loader.createLoadPlan(mContext); 880190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 881e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) { 88265c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome); 883190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 884190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack = sInstanceLoadPlan.getTaskStack(); 885190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 886f0d1c44a59a10707baa0cca8dd377302260710c1Winson // Update the header bar if necessary 887b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); 888f0d1c44a59a10707baa0cca8dd377302260710c1Winson 889190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Prepare the dummy stack for the transition 890eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mDummyStackView.updateLayoutForStack(stack); 89136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm.VisibilityReport stackVr = 892190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mDummyStackView.computeStackVisibilityReport(); 893bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi 894bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi if (!animate) { 895bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1); 896bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, opts, false /* fromHome */, 897bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi false /* fromSearchHome */, false /* fromThumbnail*/, stackVr); 898bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi return; 899bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi } 900bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi 9014b057c6787624b75613769a857ccdf51114bb7f2Winson boolean hasRecentTasks = stack.getTaskCount() > 0; 902190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks; 903190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 904190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (useThumbnailTransition) { 905190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Try starting with a thumbnail transition 906190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack, 907190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mDummyStackView); 908190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (opts != null) { 909190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, false /* fromHome */, 910190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromSearchHome */, true /* fromThumbnail */, stackVr); 911190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 912190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Fall through below to the non-thumbnail transition 913190fe3bf88388fcb109af64571e3baa0d01f1c37Winson useThumbnailTransition = false; 914190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 915190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 916190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 917190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (!useThumbnailTransition) { 918190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // If there is no thumbnail transition, but is launching from home into recents, then 919190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // use a quick home transition and do the animation from home 920d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (hasRecentTasks) { 9215da4347b41b105dc6c6c01bf2810af3ce3013229Winson SystemServicesProxy ssp = Recents.getSystemServices(); 922e7f138c7f0a190c86cec10fb32fa106aacae4093Winson String homeActivityPackage = ssp.getHomeActivityPackageName(); 923d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson String searchWidgetPackage = null; 924d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (RecentsDebugFlags.Static.EnableSearchBar) { 925d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson searchWidgetPackage = Prefs.getString(mContext, 926d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null); 927d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson } else { 928d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget(); 929d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (searchWidgetInfo != null) { 930d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson searchWidgetPackage = searchWidgetInfo.provider.getPackageName(); 931d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson } 932d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson } 933190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 934190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Determine whether we are coming from a search owned home activity 935190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean fromSearchHome = (homeActivityPackage != null) && 936190fe3bf88388fcb109af64571e3baa0d01f1c37Winson homeActivityPackage.equals(searchWidgetPackage); 937190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome); 938190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome, 939190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromThumbnail */, stackVr); 940190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 941190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Otherwise we do the normal fade from an unknown source 942190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts = getUnknownTransitionActivityOptions(); 943190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, true /* fromHome */, 944190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromSearchHome */, false /* fromThumbnail */, stackVr); 945190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 946190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 947190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mLastToggleTime = SystemClock.elapsedRealtime(); 948190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 949190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 950190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 951190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Starts the recents activity. 952190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 953190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, 954190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail, 95536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm.VisibilityReport vr) { 956190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the configuration based on the launch options 95753ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 95853ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsActivityLaunchState launchState = config.getLaunchState(); 959190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromHome = fromSearchHome || fromHome; 960190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromSearchHome = fromSearchHome; 961190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromAppWithThumbnail = fromThumbnail; 962190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1; 963190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedWithAltTab = mTriggeredFromAltTab; 964190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews; 965190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedNumVisibleTasks = vr.numVisibleTasks; 966190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails; 967190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedHasConfigurationChanged = false; 968b1e71d09f24be2c18120146eaae1ffd9444feb9aWinson launchState.launchedViaDragGesture = mDraggingInRecents; 969e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi launchState.launchedWhileDocking = mLaunchedWhileDocking; 970190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 971190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Intent intent = new Intent(); 972b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName); 973190fe3bf88388fcb109af64571e3baa0d01f1c37Winson intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 974190fe3bf88388fcb109af64571e3baa0d01f1c37Winson | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 975190fe3bf88388fcb109af64571e3baa0d01f1c37Winson | Intent.FLAG_ACTIVITY_TASK_ON_HOME); 976b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan 977190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (opts != null) { 978190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT); 979190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 980190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext.startActivityAsUser(intent, UserHandle.CURRENT); 981190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 982190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mCanReuseTaskStackViews = true; 983cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi EventBus.getDefault().send(new RecentsActivityStartingEvent()); 984190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 985190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 9863fb67562c548662910160d5672b1b9558bd6571cWinson /**** OnAnimationFinishedListener Implementation ****/ 9871a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski 9881a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski @Override 9891a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski public void onAnimationFinished() { 9901a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent()); 9911a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski } 992190fe3bf88388fcb109af64571e3baa0d01f1c37Winson} 993