RecentsImpl.java revision b94443d876d3c9575e88078d0e537bb385f79ca4
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; 22d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport android.appwidget.AppWidgetProviderInfo; 23190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.ActivityNotFoundException; 24190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Context; 25190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Intent; 26190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.res.Resources; 27190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Bitmap; 28190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Canvas; 29190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Rect; 303150e574e6e903a17193e0b90433d69c0e20ae4cWinsonimport android.graphics.RectF; 31190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.Handler; 32190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.SystemClock; 33190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.UserHandle; 341b58561f66a9453754b1b419296899fdc08b4c93Winsonimport android.util.Log; 35190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.util.MutableBoolean; 36d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynskiimport android.view.AppTransitionAnimationSpec; 37190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.LayoutInflater; 38190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.View; 39190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.internal.logging.MetricsLogger; 40190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.Prefs; 41190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.R; 42190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.SystemUIApplication; 43412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.EventBus; 441b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; 45412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.HideRecentsEvent; 460d14d4da91c3d8b1221269712d5abf43a7cf9f31Winsonimport com.android.systemui.recents.events.activity.IterateRecentsEvent; 47412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.ToggleRecentsEvent; 48190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 49190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.ScreenPinningRequestEvent; 50dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; 51dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEvent; 526b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinsonimport com.android.systemui.recents.misc.DozeTrigger; 53ab84fc56114c0963c6f701de9725f5413ab76da9Winsonimport com.android.systemui.recents.misc.ForegroundThread; 54190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.misc.SystemServicesProxy; 55190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoadPlan; 56190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoader; 57190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.Task; 58190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskGrouping; 59190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskStack; 6036a5a2c7003ef8157f276b411c3fda47ad2f75e3Winsonimport com.android.systemui.recents.views.TaskStackLayoutAlgorithm; 611b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.views.TaskStackView; 62190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewHeader; 63190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewTransform; 64d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport com.android.systemui.statusbar.BaseStatusBar; 65190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.statusbar.phone.PhoneStatusBar; 66190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 67190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport java.util.ArrayList; 68190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 691b58561f66a9453754b1b419296899fdc08b4c93Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 701b58561f66a9453754b1b419296899fdc08b4c93Winson 71190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/** 72190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of the Recents component for the current user. For secondary users, this can 73190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * be called remotely from the system user. 74190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 751a4dfe593aafda057ac9cb3086b84588d88cd09fFilip Gruszczynskipublic class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements 761a4dfe593aafda057ac9cb3086b84588d88cd09fFilip Gruszczynski ActivityOptions.OnAnimationFinishedListener { 77190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 78190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private final static String TAG = "RecentsImpl"; 796b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The minimum amount of time between each recents button press that we will handle 806b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson private final static int MIN_TOGGLE_DELAY_MS = 350; 816b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The duration within which the user releasing the alt tab (from when they pressed alt tab) 826b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // that the fast alt-tab animation will run. If the user's alt-tab takes longer than this 836b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // duration, then we will toggle recents after this duration. 846b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson private final static int FAST_ALT_TAB_DELAY_MS = 225; 85190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 86190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public final static String RECENTS_PACKAGE = "com.android.systemui"; 87190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity"; 88190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 89190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 90190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of ITaskStackListener, that allows us to listen for changes to the system 91190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * task stacks and update recents accordingly. 92190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 93190fe3bf88388fcb109af64571e3baa0d01f1c37Winson class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable { 94190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Handler mHandler; 95190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 96190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public TaskStackListenerImpl(Handler handler) { 97190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler = handler; 98190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 99190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 100190fe3bf88388fcb109af64571e3baa0d01f1c37Winson @Override 101190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onTaskStackChanged() { 102190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Debounce any task stack changes 103190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler.removeCallbacks(this); 104190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler.post(this); 105190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 106190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 10703ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale @Override 10803ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale public void onActivityPinned() { 10903ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale } 11003ce863860e3e45781e44317d8b2f42a08f40512Wale Ogunwale 111190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** Preloads the next task */ 112190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void run() { 113190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // TODO: Temporarily skip this if multi stack is enabled 114190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /* 115190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsConfiguration config = RecentsConfiguration.getInstance(); 116190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) { 117e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 118e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 119190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask(); 120190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 121190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Load the next task only if we aren't svelte 122190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 123190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.preloadTasks(plan, true); 124190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 125190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // This callback is made when a new activity is launched and the old one is paused 126190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // so ignore the current activity and try and preload the thumbnail for the 127190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // previous one. 128190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTaskInfo != null) { 129190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.runningTaskId = runningTaskInfo.id; 130190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 131190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTasks = 2; 132190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTaskThumbnails = 2; 133190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 134190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadPausedActivities = true; 135190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.loadTasks(mContext, plan, launchOpts); 136190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 137190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 138190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 139190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 140190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 141e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private static RecentsTaskLoadPlan sInstanceLoadPlan; 142190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 143190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Context mContext; 144190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Handler mHandler; 145190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStackListenerImpl mTaskStackListener; 146190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsAppWidgetHost mAppWidgetHost; 147190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean mBootCompleted; 148190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean mCanReuseTaskStackViews = true; 149dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean mDraggingInRecents; 150435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi boolean mReloadTasks; 151190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 152190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Task launching 153190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mSearchBarBounds = new Rect(); 154190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mTaskStackBounds = new Rect(); 155190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mLastTaskViewBounds = new Rect(); 156190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskViewTransform mTmpTransform = new TaskViewTransform(); 157190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mStatusBarHeight; 158190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mNavBarHeight; 159190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mNavBarWidth; 160190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mTaskBarHeight; 161190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 162190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Header (for transition) 163190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskViewHeader mHeaderBar; 164190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final Object mHeaderBarLock = new Object(); 165190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStackView mDummyStackView; 166190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 167190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Variables to keep track of if we need to start recents after binding 168190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean mTriggeredFromAltTab; 169190fe3bf88388fcb109af64571e3baa0d01f1c37Winson long mLastToggleTime; 1706b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson DozeTrigger mFastAltTabTrigger = new DozeTrigger(FAST_ALT_TAB_DELAY_MS, new Runnable() { 1716b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson @Override 1726b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson public void run() { 1736b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // When this fires, then the user has not released alt-tab for at least 1746b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // FAST_ALT_TAB_DELAY_MS milliseconds 175435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi showRecents(mTriggeredFromAltTab, false /* draggingInRecents */, true /* animate */, 176435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi false /* reloadTasks */); 1776b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 1786b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson }); 179190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 180190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap mThumbnailTransitionBitmapCache; 181190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task mThumbnailTransitionBitmapCacheKey; 182190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 183190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public RecentsImpl(Context context) { 184190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext = context; 185190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler = new Handler(); 1861b58561f66a9453754b1b419296899fdc08b4c93Winson mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID); 187190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 188ab84fc56114c0963c6f701de9725f5413ab76da9Winson // Initialize the static foreground thread 189ab84fc56114c0963c6f701de9725f5413ab76da9Winson ForegroundThread.get(); 190ab84fc56114c0963c6f701de9725f5413ab76da9Winson 191190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Register the task stack listener 192190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTaskStackListener = new TaskStackListenerImpl(mHandler); 193e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 194e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.registerTaskStackListener(mTaskStackListener); 195190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 196190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Initialize the static configuration resources 197b94443d876d3c9575e88078d0e537bb385f79ca4Winson reloadHeaderBarLayout(); 198b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 199190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 200190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // When we start, preload the data associated with the previous recent tasks. 201190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // We can use a new plan since the caches will be the same. 202e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 203190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 204190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.preloadTasks(plan, true /* isTopTaskHome */); 205190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 206296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung launchOpts.numVisibleTasks = loader.getIconCacheSize(); 207190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize(); 208190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 209190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.loadTasks(mContext, plan, launchOpts); 210190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 211190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 212190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onBootCompleted() { 213190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mBootCompleted = true; 214b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 215190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 216190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 217190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onConfigurationChanged() { 218b94443d876d3c9575e88078d0e537bb385f79ca4Winson reloadHeaderBarLayout(); 219b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 220190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Don't reuse task stack views if the configuration changes 221190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mCanReuseTaskStackViews = false; 22253ec42cb17693b2d631746e1e5d31021a3359163Winson Recents.getConfiguration().updateOnConfigurationChange(); 223190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 224190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 225190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 226190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * This is only called from the system user's Recents. Secondary users will instead proxy their 227190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * visibility change events through to the system user via 228190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}. 229190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 230190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onVisibilityChanged(Context context, boolean visible) { 231190fe3bf88388fcb109af64571e3baa0d01f1c37Winson SystemUIApplication app = (SystemUIApplication) context; 232190fe3bf88388fcb109af64571e3baa0d01f1c37Winson PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); 233190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (statusBar != null) { 234190fe3bf88388fcb109af64571e3baa0d01f1c37Winson statusBar.updateRecentsVisibility(visible); 235190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 236190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 237190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 238190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 239190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * This is only called from the system user's Recents. Secondary users will instead proxy their 240190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * visibility change events through to the system user via 241190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}. 242190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 243190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onStartScreenPinning(Context context) { 244190fe3bf88388fcb109af64571e3baa0d01f1c37Winson SystemUIApplication app = (SystemUIApplication) context; 245190fe3bf88388fcb109af64571e3baa0d01f1c37Winson PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); 246190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (statusBar != null) { 247190fe3bf88388fcb109af64571e3baa0d01f1c37Winson statusBar.showScreenPinningRequest(false); 248190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 249190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 250190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 251bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, 252435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi boolean animate, boolean reloadTasks) { 253190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTriggeredFromAltTab = triggeredFromAltTab; 254dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDraggingInRecents = draggingInRecents; 255435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi mReloadTasks = reloadTasks; 2566b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (mFastAltTabTrigger.hasTriggered()) { 2576b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // We are calling this from the doze trigger, so just fall through to show Recents 2586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.resetTrigger(); 2596b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } else if (mFastAltTabTrigger.isDozing()) { 2606b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // We are dozing but haven't yet triggered, ignore this if this is not another alt-tab, 2616b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // otherwise, this is an additional tab (alt-tab*), which means that we should trigger 2626b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // immediately (fall through and disable the pending trigger) 2636b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // TODO: This is tricky, we need to handle the tab key, but Recents has not yet started 2646b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // so we may actually additional signal to handle multiple quick tab cases. The 2656b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // severity of this is inversely proportional to the FAST_ALT_TAB_DELAY_MS 2666b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // duration though 2676b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (!triggeredFromAltTab) { 2686b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 2696b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 2706b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.stopDozing(); 2716b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } else { 2726b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Otherwise, the doze trigger is not running, and if this is an alt tab, we should 2736b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // start the trigger and then wait for the hide (or for it to elapse) 2746b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (triggeredFromAltTab) { 2756b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.startDozing(); 2766b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 2776b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 2786b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 279190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 280190fe3bf88388fcb109af64571e3baa0d01f1c37Winson try { 281190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Check if the top task is in the home stack, and start the recents activity 282e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 283e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 284190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean isTopTaskHome = new MutableBoolean(true); 285e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) { 286bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, isTopTaskHome.value, animate); 287190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 288190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } catch (ActivityNotFoundException e) { 2891b58561f66a9453754b1b419296899fdc08b4c93Winson Log.e(TAG, "Failed to launch RecentsActivity", e); 290190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 291190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 292190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 293190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 294190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (mBootCompleted) { 2956b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) { 2966b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The user has released alt-tab before the trigger has run, so just show the next 2976b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // task immediately 2986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson showNextTask(); 2996b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 3006b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Cancel the fast alt-tab trigger 3016b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.stopDozing(); 3026b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.resetTrigger(); 3036b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 3046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 3056b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 306190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Defer to the activity to handle hiding recents, if it handles it, then it must still 307190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // be visible 308e7f138c7f0a190c86cec10fb32fa106aacae4093Winson EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab, 309412e18058dc2cd5779d2451fce7fd74631f9e237Winson triggeredFromHomeKey)); 310190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 311190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 312190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 313190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void toggleRecents() { 3146b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Skip this toggle if we are already waiting to trigger recents via alt-tab 3156b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (mFastAltTabTrigger.isDozing()) { 3166b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 3176b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 3186b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 319dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDraggingInRecents = false; 320190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTriggeredFromAltTab = false; 321190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 322190fe3bf88388fcb109af64571e3baa0d01f1c37Winson try { 323e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 324e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 325190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean isTopTaskHome = new MutableBoolean(true); 326e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { 3275da4347b41b105dc6c6c01bf2810af3ce3013229Winson RecentsConfiguration config = Recents.getConfiguration(); 3285da4347b41b105dc6c6c01bf2810af3ce3013229Winson RecentsActivityLaunchState launchState = config.getLaunchState(); 329ead5c0fc20e5c60a68cd017af0b8eacaf1167a1cWinson Chung if (!launchState.launchedWithAltTab) { 3300d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // Notify recents to move onto the next task 3310d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson EventBus.getDefault().post(new IterateRecentsEvent()); 3320d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } else { 3330d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // If the user has toggled it too quickly, then just eat up the event here (it's 3340d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // better than showing a janky screenshot). 3350d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // NOTE: Ideally, the screenshot mechanism would take the window transform into 3360d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // account 3376b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) { 3380d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson return; 3390d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 3400d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson 3410d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson EventBus.getDefault().post(new ToggleRecentsEvent()); 3420d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson mLastToggleTime = SystemClock.elapsedRealtime(); 3430d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 344190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return; 345190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 3460d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // If the user has toggled it too quickly, then just eat up the event here (it's 3470d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // better than showing a janky screenshot). 3480d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // NOTE: Ideally, the screenshot mechanism would take the window transform into 3490d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // account 3506b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) { 3510d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson return; 3520d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 3530d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson 354190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Otherwise, start the recents activity 355bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */); 356d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson 357d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson // Only close the other system windows if we are actually showing recents 358d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS); 3590d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson mLastToggleTime = SystemClock.elapsedRealtime(); 360190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 361190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } catch (ActivityNotFoundException e) { 3621b58561f66a9453754b1b419296899fdc08b4c93Winson Log.e(TAG, "Failed to launch RecentsActivity", e); 363190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 364190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 365190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 366190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void preloadRecents() { 367190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Preload only the raw task list into a new load plan (which will be consumed by the 368190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // RecentsActivity) only if there is a task to animate to. 369e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 370e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 371190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean topTaskHome = new MutableBoolean(true); 372e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 373190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = loader.createLoadPlan(mContext); 374e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) { 375190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan.preloadRawTasks(topTaskHome.value); 376190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value); 377190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack = sInstanceLoadPlan.getTaskStack(); 378250608a5cd08862f4752a924d51710805850db8aWinson if (stack.getStackTaskCount() > 0) { 379ab84fc56114c0963c6f701de9725f5413ab76da9Winson // We try and draw the thumbnail transition bitmap in parallel before 380ab84fc56114c0963c6f701de9725f5413ab76da9Winson // toggle/show recents is called 381190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView); 382190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 383190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 384190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 385190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 386190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void cancelPreloadingRecents() { 387190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Do nothing 388190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 389190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 390dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void onDraggingInRecents(float distanceFromTop) { 391dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop)); 392dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 393dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 394dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void onDraggingInRecentsEnded(float velocity) { 395dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity)); 396dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 397dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 3986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson /** 3996b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson * Transitions to the next recent task in the stack. 4006b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson */ 4016b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson public void showNextTask() { 4026b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson SystemServicesProxy ssp = Recents.getSystemServices(); 4036b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson RecentsTaskLoader loader = Recents.getTaskLoader(); 4046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 4056b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson loader.preloadTasks(plan, true /* isTopTaskHome */); 4066b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson TaskStack focusedStack = plan.getTaskStack(); 4076b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4086b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there are no tasks in the focused stack 409250608a5cd08862f4752a924d51710805850db8aWinson if (focusedStack == null || focusedStack.getStackTaskCount() == 0) return; 4106b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4116b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask(); 4126b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there is no running task 4136b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (runningTask == null) return; 4146b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4156b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Find the task in the recents list 416e86deb8adb022ba7721a1af1112d3a45e757095cWinson boolean isTopTaskHome = SystemServicesProxy.isHomeStack(runningTask.stackId); 417250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = focusedStack.getStackTasks(); 4186b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson Task toTask = null; 4196b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityOptions launchOpts = null; 4206b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson int taskCount = tasks.size(); 4216b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson for (int i = taskCount - 1; i >= 1; i--) { 4226b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson Task task = tasks.get(i); 423e86deb8adb022ba7721a1af1112d3a45e757095cWinson if (isTopTaskHome) { 424e86deb8adb022ba7721a1af1112d3a45e757095cWinson toTask = tasks.get(i - 1); 425e86deb8adb022ba7721a1af1112d3a45e757095cWinson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 426e86deb8adb022ba7721a1af1112d3a45e757095cWinson R.anim.recents_launch_next_affiliated_task_target, 427e86deb8adb022ba7721a1af1112d3a45e757095cWinson R.anim.recents_fast_toggle_app_home_exit); 428e86deb8adb022ba7721a1af1112d3a45e757095cWinson break; 429e86deb8adb022ba7721a1af1112d3a45e757095cWinson } else if (task.key.id == runningTask.id) { 4306b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson toTask = tasks.get(i - 1); 4316b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 4326b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_target, 4336b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_source); 4346b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson break; 4356b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4366b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4376b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4386b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there is no next task 4396b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (toTask == null) { 4406b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ssp.startInPlaceAnimationOnFrontMostApplication( 4416b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityOptions.makeCustomInPlaceAnimation(mContext, 4426b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_bounce)); 4436b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 4446b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4456b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4466b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Launch the task 447296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts); 4486b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4496b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4506b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson /** 4516b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson * Transitions to the next affiliated task. 4526b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson */ 453190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showRelativeAffiliatedTask(boolean showNextTask) { 454e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 455e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 456190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 457190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.preloadTasks(plan, true /* isTopTaskHome */); 458190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack focusedStack = plan.getTaskStack(); 459190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 460190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there are no tasks in the focused stack 461250608a5cd08862f4752a924d51710805850db8aWinson if (focusedStack == null || focusedStack.getStackTaskCount() == 0) return; 462190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 463e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask(); 464190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there is no running task (can't determine affiliated tasks in this case) 465190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTask == null) return; 466190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if the running task is in the home stack (optimization) 4675510f6c1b9c20483e1507147eed7b24ac8bb6363Winson if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return; 468190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 469190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Find the task in the recents list 470250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = focusedStack.getStackTasks(); 471190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task toTask = null; 472190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions launchOpts = null; 473190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskCount = tasks.size(); 474190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int numAffiliatedTasks = 0; 475190fe3bf88388fcb109af64571e3baa0d01f1c37Winson for (int i = 0; i < taskCount; i++) { 476190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task task = tasks.get(i); 477190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (task.key.id == runningTask.id) { 478190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskGrouping group = task.group; 479190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task.TaskKey toTaskKey; 480190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (showNextTask) { 481190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTaskKey = group.getNextTaskInGroup(task); 482190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 483190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_target, 484190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_source); 485190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 486190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTaskKey = group.getPrevTaskInGroup(task); 487190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 488190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_target, 489190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_source); 490190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 491190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTaskKey != null) { 492190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTask = focusedStack.findTaskWithId(toTaskKey.id); 493190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 494190fe3bf88388fcb109af64571e3baa0d01f1c37Winson numAffiliatedTasks = group.getTaskCount(); 495190fe3bf88388fcb109af64571e3baa0d01f1c37Winson break; 496190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 497190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 498190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 499190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there is no next task 500190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTask == null) { 501190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (numAffiliatedTasks > 1) { 502190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (showNextTask) { 503e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.startInPlaceAnimationOnFrontMostApplication( 504190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions.makeCustomInPlaceAnimation(mContext, 505190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_bounce)); 506190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 507e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.startInPlaceAnimationOnFrontMostApplication( 508190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions.makeCustomInPlaceAnimation(mContext, 509190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_bounce)); 510190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 511190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 512190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return; 513190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 514190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 515190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of actually launched affiliated tasks 516190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1); 517190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 518190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Launch the task 519296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts); 520190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 521190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 522190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showNextAffiliatedTask() { 523190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of when the affiliated task is triggered 524190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_next", 1); 525190fe3bf88388fcb109af64571e3baa0d01f1c37Winson showRelativeAffiliatedTask(true); 526190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 527190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 528190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showPrevAffiliatedTask() { 529190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of when the affiliated task is triggered 530190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1); 531190fe3bf88388fcb109af64571e3baa0d01f1c37Winson showRelativeAffiliatedTask(false); 532190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 533190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 534e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) { 53575b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi SystemServicesProxy ssp = Recents.getSystemServices(); 53675b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 537e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson boolean screenPinningActive = ssp.isScreenPinningActive(); 538e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson boolean isTopTaskHome = SystemServicesProxy.isHomeStack(topTask.stackId); 539e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson if (topTask != null && !isTopTaskHome && !screenPinningActive) { 540213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggi ssp.moveTaskToDockedStack(topTask.id, stackCreateMode, initialBounds); 541435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi showRecents(false /* triggeredFromAltTab */, draggingInRecents, false /* animate */, 542435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi true /* reloadTasks*/); 543e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson return true; 54475b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi } 545e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson return false; 54675b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi } 54775b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi 548190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 549190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Returns the preloaded load plan and invalidates it. 550190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 551190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public static RecentsTaskLoadPlan consumeInstanceLoadPlan() { 552190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = sInstanceLoadPlan; 553190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = null; 554190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return plan; 555190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 556190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 557190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 558b94443d876d3c9575e88078d0e537bb385f79ca4Winson * Reloads all the layouts for the header bar transition. 559b94443d876d3c9575e88078d0e537bb385f79ca4Winson */ 560b94443d876d3c9575e88078d0e537bb385f79ca4Winson private void reloadHeaderBarLayout() { 561b94443d876d3c9575e88078d0e537bb385f79ca4Winson Resources res = mContext.getResources(); 562b94443d876d3c9575e88078d0e537bb385f79ca4Winson LayoutInflater inflater = LayoutInflater.from(mContext); 563b94443d876d3c9575e88078d0e537bb385f79ca4Winson 564b94443d876d3c9575e88078d0e537bb385f79ca4Winson mStatusBarHeight = res.getDimensionPixelSize( 565b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.status_bar_height); 566b94443d876d3c9575e88078d0e537bb385f79ca4Winson mNavBarHeight = res.getDimensionPixelSize( 567b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.navigation_bar_height); 568b94443d876d3c9575e88078d0e537bb385f79ca4Winson mNavBarWidth = res.getDimensionPixelSize( 569b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.navigation_bar_width); 570b94443d876d3c9575e88078d0e537bb385f79ca4Winson mTaskBarHeight = res.getDimensionPixelSize( 571b94443d876d3c9575e88078d0e537bb385f79ca4Winson R.dimen.recents_task_bar_height); 572b94443d876d3c9575e88078d0e537bb385f79ca4Winson mDummyStackView = new TaskStackView(mContext, new TaskStack()); 573b94443d876d3c9575e88078d0e537bb385f79ca4Winson mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, 574b94443d876d3c9575e88078d0e537bb385f79ca4Winson null, false); 575b94443d876d3c9575e88078d0e537bb385f79ca4Winson } 576b94443d876d3c9575e88078d0e537bb385f79ca4Winson 577b94443d876d3c9575e88078d0e537bb385f79ca4Winson /** 578190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Prepares the header bar layout for the next transition, if the task view bounds has changed 579190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * since the last call, it will attempt to re-measure and layout the header bar to the new size. 580190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * 581190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one 582190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * is not already bound (can be expensive) 583f0d1c44a59a10707baa0cca8dd377302260710c1Winson * @param stack the stack to initialize the stack layout with 584190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 585b94443d876d3c9575e88078d0e537bb385f79ca4Winson private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, 586b94443d876d3c9575e88078d0e537bb385f79ca4Winson TaskStack stack) { 58753ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 588e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 589e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Rect windowRect = ssp.getWindowRect(); 590190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 591190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the configuration for the current state 592931c51f54599a227422b2a1c71e922e1458e0291Winson Chung config.update(windowRect); 593190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 594d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) { 595190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Try and pre-emptively bind the search widget on startup to ensure that we 596190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // have the right thumbnail bounds to animate to. 597190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Note: We have to reload the widget id before we get the task stack bounds below 598e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) { 59953ec42cb17693b2d631746e1e5d31021a3359163Winson config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds); 600190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 601190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 602190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect systemInsets = new Rect(0, mStatusBarHeight, 60353ec42cb17693b2d631746e1e5d31021a3359163Winson (config.hasTransposedNavBar ? mNavBarWidth : 0), 60453ec42cb17693b2d631746e1e5d31021a3359163Winson (config.hasTransposedNavBar ? 0 : mNavBarHeight)); 60553ec42cb17693b2d631746e1e5d31021a3359163Winson config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right, 606190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mSearchBarBounds, mTaskStackBounds); 607190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 608190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Rebind the header bar and draw it for the transition 60936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm(); 610190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect taskStackBounds = new Rect(mTaskStackBounds); 611190fe3bf88388fcb109af64571e3baa0d01f1c37Winson algo.setSystemInsets(systemInsets); 612f0d1c44a59a10707baa0cca8dd377302260710c1Winson if (stack != null) { 613f0d1c44a59a10707baa0cca8dd377302260710c1Winson algo.initialize(taskStackBounds, 614f0d1c44a59a10707baa0cca8dd377302260710c1Winson TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack)); 615f0d1c44a59a10707baa0cca8dd377302260710c1Winson } 616190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect taskViewBounds = algo.getUntransformedTaskViewBounds(); 617190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (!taskViewBounds.equals(mLastTaskViewBounds)) { 618190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mLastTaskViewBounds.set(taskViewBounds); 619190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 620190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskViewWidth = taskViewBounds.width(); 621190fe3bf88388fcb109af64571e3baa0d01f1c37Winson synchronized (mHeaderBarLock) { 622190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.measure( 623190fe3bf88388fcb109af64571e3baa0d01f1c37Winson View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY), 624190fe3bf88388fcb109af64571e3baa0d01f1c37Winson View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY)); 625190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight); 626190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 627190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 628190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 629190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 630190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 631190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Preloads the icon of a task. 632190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 633190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void preloadIcon(ActivityManager.RunningTaskInfo task) { 634190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Ensure that we load the running task's icon 635190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 636190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.runningTaskId = task.id; 637190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.loadThumbnails = false; 638190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 639e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts); 640190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 641190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 642190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 643190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Caches the header thumbnail used for a window animation asynchronously into 644190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link #mThumbnailTransitionBitmapCache}. 645190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 646190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask, 647190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack, TaskStackView stackView) { 648190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preloadIcon(topTask); 649190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 650190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the header bar if necessary 651b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); 652190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 653190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the destination rect 654eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mDummyStackView.updateLayoutForStack(stack); 655190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final Task toTask = new Task(); 656190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, 657190fe3bf88388fcb109af64571e3baa0d01f1c37Winson topTask.id, toTask); 6583fb67562c548662910160d5672b1b9558bd6571cWinson ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() { 659190fe3bf88388fcb109af64571e3baa0d01f1c37Winson @Override 660ab84fc56114c0963c6f701de9725f5413ab76da9Winson public void run() { 661ab84fc56114c0963c6f701de9725f5413ab76da9Winson final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform); 662ab84fc56114c0963c6f701de9725f5413ab76da9Winson mHandler.post(new Runnable() { 663ab84fc56114c0963c6f701de9725f5413ab76da9Winson @Override 664ab84fc56114c0963c6f701de9725f5413ab76da9Winson public void run() { 665ab84fc56114c0963c6f701de9725f5413ab76da9Winson mThumbnailTransitionBitmapCache = transitionBitmap; 666ab84fc56114c0963c6f701de9725f5413ab76da9Winson mThumbnailTransitionBitmapCacheKey = toTask; 667ab84fc56114c0963c6f701de9725f5413ab76da9Winson } 668ab84fc56114c0963c6f701de9725f5413ab76da9Winson }); 669190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 670ab84fc56114c0963c6f701de9725f5413ab76da9Winson }); 671190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 672190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 673190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 674190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for a unknown state->recents transition. 675190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 676190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getUnknownTransitionActivityOptions() { 677190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 678190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_unknown_enter, 679190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_unknown_exit, 6803fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 681190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 682190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 683190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 684190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for a home->recents transition. 685190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 686190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) { 687190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (fromSearchHome) { 688190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 689190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_search_launcher_enter, 690190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_search_launcher_exit, 6913fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 692190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 693190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 694190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_launcher_enter, 695190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_launcher_exit, 6963fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 697190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 698190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 699190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 700190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for an app->recents transition. 701190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 702190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getThumbnailTransitionActivityOptions( 703190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) { 704d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) { 705d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>(); 706d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski stackView.getScroller().setStackScrollToInitialState(); 707250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = stack.getStackTasks(); 708d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski for (int i = tasks.size() - 1; i >= 0; i--) { 709d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Task task = tasks.get(i); 710387aac6ad7bde21f2c2510cb8a2f3af3959721e0Winson if (task.isFreeformTask()) { 711d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task, 712d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski stackView.getScroller().getStackScroll(), mTmpTransform, null); 713d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Rect toTaskRect = new Rect(); 714d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski mTmpTransform.rect.round(toTaskRect); 715d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform); 716d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect)); 717d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 718d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 719d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()]; 720d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski specs.toArray(specsArray); 721d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, 7223fb67562c548662910160d5672b1b9558bd6571cWinson specsArray, mHandler, null, this); 723d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } else { 724d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski // Update the destination rect 725d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Task toTask = new Task(); 726d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, 727d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski topTask.id, toTask); 728d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski RectF toTaskRect = toTransform.rect; 729d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform); 730d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski if (thumbnail != null) { 731d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, 732d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski thumbnail, (int) toTaskRect.left, (int) toTaskRect.top, 7333fb67562c548662910160d5672b1b9558bd6571cWinson (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null); 734d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 735d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski // If both the screenshot and thumbnail fails, then just fall back to the default transition 736d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return getUnknownTransitionActivityOptions(); 737d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 738d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 739190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 740d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask, 741d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski TaskViewTransform toTransform) { 742190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap thumbnail; 743190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (mThumbnailTransitionBitmapCacheKey != null 744190fe3bf88388fcb109af64571e3baa0d01f1c37Winson && mThumbnailTransitionBitmapCacheKey.key != null 745190fe3bf88388fcb109af64571e3baa0d01f1c37Winson && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) { 746190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = mThumbnailTransitionBitmapCache; 747190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mThumbnailTransitionBitmapCacheKey = null; 748190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mThumbnailTransitionBitmapCache = null; 749190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 750190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preloadIcon(topTask); 751190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform); 752190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 753d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return thumbnail; 754190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 755190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 756190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 757190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Returns the transition rect for the given task id. 758190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 759190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, 760190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStackView stackView, int runningTaskId, Task runningTaskOut) { 761190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Find the running task in the TaskStack 762190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task task = null; 763250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = stack.getStackTasks(); 764190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTaskId != -1) { 765190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Otherwise, try and find the task with the 766190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskCount = tasks.size(); 767190fe3bf88388fcb109af64571e3baa0d01f1c37Winson for (int i = taskCount - 1; i >= 0; i--) { 768190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task t = tasks.get(i); 769190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (t.key.id == runningTaskId) { 770190fe3bf88388fcb109af64571e3baa0d01f1c37Winson task = t; 771190fe3bf88388fcb109af64571e3baa0d01f1c37Winson runningTaskOut.copyFrom(t); 772190fe3bf88388fcb109af64571e3baa0d01f1c37Winson break; 773190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 774190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 775190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 776190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (task == null) { 777190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // If no task is specified or we can not find the task just use the front most one 778190fe3bf88388fcb109af64571e3baa0d01f1c37Winson task = tasks.get(tasks.size() - 1); 779190fe3bf88388fcb109af64571e3baa0d01f1c37Winson runningTaskOut.copyFrom(task); 780190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 781190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 782190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Get the transform for the running task 783190fe3bf88388fcb109af64571e3baa0d01f1c37Winson stackView.getScroller().setStackScrollToInitialState(); 784190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task, 785190fe3bf88388fcb109af64571e3baa0d01f1c37Winson stackView.getScroller().getStackScroll(), mTmpTransform, null); 786190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return mTmpTransform; 787190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 788190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 789190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 790190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Draws the header of a task used for the window animation into a bitmap. 791190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 792190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) { 793190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTransform != null && toTask.key != null) { 794190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap thumbnail; 795190fe3bf88388fcb109af64571e3baa0d01f1c37Winson synchronized (mHeaderBarLock) { 796509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung int toHeaderWidth = (int) toTransform.rect.width(); 797190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); 798509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(), 799509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung (int) toTransform.rect.height()); 800190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, 801190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap.Config.ARGB_8888); 802c742f973b1e506732911c156c5869fd377afc5bfWinson if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { 803190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail.eraseColor(0xFFff0000); 804190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 805190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Canvas c = new Canvas(thumbnail); 806190fe3bf88388fcb109af64571e3baa0d01f1c37Winson c.scale(toTransform.scale, toTransform.scale); 807190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.rebindToTask(toTask); 808190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.draw(c); 809190fe3bf88388fcb109af64571e3baa0d01f1c37Winson c.setBitmap(null); 810190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 811190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 812190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return thumbnail.createAshmemBitmap(); 813190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 814190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return null; 815190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 816190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 817190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 818190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Shows the recents activity 819190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 820190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, 821bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi boolean isTopTaskHome, boolean animate) { 822e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 823190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 824e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we 825435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi // should always preload the tasks now. If we are dragging in recents, reload them as 826435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi // the stacks might have changed. 827435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi if (mReloadTasks || mTriggeredFromAltTab ||sInstanceLoadPlan == null) { 828e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson // Create a new load plan if preloadRecents() was never triggered 829190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = loader.createLoadPlan(mContext); 830190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 831435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi if (mReloadTasks || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) { 832190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome); 833190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 834190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack = sInstanceLoadPlan.getTaskStack(); 835190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 836f0d1c44a59a10707baa0cca8dd377302260710c1Winson // Update the header bar if necessary 837b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); 838f0d1c44a59a10707baa0cca8dd377302260710c1Winson 839190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Prepare the dummy stack for the transition 840eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mDummyStackView.updateLayoutForStack(stack); 84136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm.VisibilityReport stackVr = 842190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mDummyStackView.computeStackVisibilityReport(); 843bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi 844bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi if (!animate) { 845bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1); 846bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, opts, false /* fromHome */, 847bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi false /* fromSearchHome */, false /* fromThumbnail*/, stackVr); 848bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi return; 849bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi } 850bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi 851250608a5cd08862f4752a924d51710805850db8aWinson boolean hasRecentTasks = stack.getStackTaskCount() > 0; 852190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks; 853190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 854190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (useThumbnailTransition) { 855190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Try starting with a thumbnail transition 856190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack, 857190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mDummyStackView); 858190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (opts != null) { 859190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, false /* fromHome */, 860190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromSearchHome */, true /* fromThumbnail */, stackVr); 861190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 862190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Fall through below to the non-thumbnail transition 863190fe3bf88388fcb109af64571e3baa0d01f1c37Winson useThumbnailTransition = false; 864190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 865190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 866190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 867190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (!useThumbnailTransition) { 868190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // If there is no thumbnail transition, but is launching from home into recents, then 869190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // use a quick home transition and do the animation from home 870d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (hasRecentTasks) { 8715da4347b41b105dc6c6c01bf2810af3ce3013229Winson SystemServicesProxy ssp = Recents.getSystemServices(); 872e7f138c7f0a190c86cec10fb32fa106aacae4093Winson String homeActivityPackage = ssp.getHomeActivityPackageName(); 873d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson String searchWidgetPackage = null; 874d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (RecentsDebugFlags.Static.EnableSearchBar) { 875d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson searchWidgetPackage = Prefs.getString(mContext, 876d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null); 877d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson } else { 878d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget(); 879d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (searchWidgetInfo != null) { 880d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson searchWidgetPackage = searchWidgetInfo.provider.getPackageName(); 881d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson } 882d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson } 883190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 884190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Determine whether we are coming from a search owned home activity 885190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean fromSearchHome = (homeActivityPackage != null) && 886190fe3bf88388fcb109af64571e3baa0d01f1c37Winson homeActivityPackage.equals(searchWidgetPackage); 887190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome); 888190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome, 889190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromThumbnail */, stackVr); 890190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 891190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Otherwise we do the normal fade from an unknown source 892190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts = getUnknownTransitionActivityOptions(); 893190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, true /* fromHome */, 894190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromSearchHome */, false /* fromThumbnail */, stackVr); 895190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 896190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 897190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mLastToggleTime = SystemClock.elapsedRealtime(); 898190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 899190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 900190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 901190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Starts the recents activity. 902190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 903190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, 904190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail, 90536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm.VisibilityReport vr) { 906190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the configuration based on the launch options 90753ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 90853ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsActivityLaunchState launchState = config.getLaunchState(); 909190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromHome = fromSearchHome || fromHome; 910190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromSearchHome = fromSearchHome; 911190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromAppWithThumbnail = fromThumbnail; 912190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1; 913190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedWithAltTab = mTriggeredFromAltTab; 914190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews; 915190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedNumVisibleTasks = vr.numVisibleTasks; 916190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails; 917190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedHasConfigurationChanged = false; 918b1e71d09f24be2c18120146eaae1ffd9444feb9aWinson launchState.launchedViaDragGesture = mDraggingInRecents; 919190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 920190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Intent intent = new Intent(); 921190fe3bf88388fcb109af64571e3baa0d01f1c37Winson intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY); 922190fe3bf88388fcb109af64571e3baa0d01f1c37Winson intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 923190fe3bf88388fcb109af64571e3baa0d01f1c37Winson | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 924190fe3bf88388fcb109af64571e3baa0d01f1c37Winson | Intent.FLAG_ACTIVITY_TASK_ON_HOME); 925190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (opts != null) { 926190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT); 927190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 928190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext.startActivityAsUser(intent, UserHandle.CURRENT); 929190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 930190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mCanReuseTaskStackViews = true; 931190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 932190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 9333fb67562c548662910160d5672b1b9558bd6571cWinson /**** OnAnimationFinishedListener Implementation ****/ 9341a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski 9351a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski @Override 9361a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski public void onAnimationFinished() { 9371a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent()); 9381a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski } 939190fe3bf88388fcb109af64571e3baa0d01f1c37Winson} 940