RecentsImpl.java revision 938a50b424eb73ee96d34c96b5e2cbd11f733d7a
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 19e693aafe0511c2a7ffc571b22abeefba44046225Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 20e693aafe0511c2a7ffc571b22abeefba44046225Winson 21190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityManager; 22190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityOptions; 23d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport android.appwidget.AppWidgetProviderInfo; 24190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.ActivityNotFoundException; 25190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Context; 26190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Intent; 27190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.res.Resources; 28190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Bitmap; 29190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Canvas; 30190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Rect; 313150e574e6e903a17193e0b90433d69c0e20ae4cWinsonimport android.graphics.RectF; 32190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.Handler; 33190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.SystemClock; 34190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.UserHandle; 351b58561f66a9453754b1b419296899fdc08b4c93Winsonimport android.util.Log; 36190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.util.MutableBoolean; 37d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynskiimport android.view.AppTransitionAnimationSpec; 38190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.LayoutInflater; 39190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.View; 40b61e654b9a46e79827355104760a3ac5228380bcWinsonimport android.view.ViewConfiguration; 41c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 42190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.internal.logging.MetricsLogger; 43190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.Prefs; 44190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.R; 45190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.SystemUIApplication; 46412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.EventBus; 47899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggiimport com.android.systemui.recents.events.activity.DockedTopTaskEvent; 481b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; 49412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.HideRecentsEvent; 500d14d4da91c3d8b1221269712d5abf43a7cf9f31Winsonimport com.android.systemui.recents.events.activity.IterateRecentsEvent; 51b61e654b9a46e79827355104760a3ac5228380bcWinsonimport com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent; 52cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggiimport com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; 53412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.ToggleRecentsEvent; 54190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 55190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.ScreenPinningRequestEvent; 56dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; 57dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEvent; 586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinsonimport com.android.systemui.recents.misc.DozeTrigger; 59ab84fc56114c0963c6f701de9725f5413ab76da9Winsonimport com.android.systemui.recents.misc.ForegroundThread; 60190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.misc.SystemServicesProxy; 61938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kimimport com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; 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; 69e693aafe0511c2a7ffc571b22abeefba44046225Winsonimport com.android.systemui.recents.views.TaskStackViewScroller; 70190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewHeader; 71190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewTransform; 72d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport com.android.systemui.statusbar.BaseStatusBar; 73cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggiimport com.android.systemui.statusbar.phone.NavigationBarGestureHelper; 74190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.statusbar.phone.PhoneStatusBar; 75190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 76190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport java.util.ArrayList; 77190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 78190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/** 79190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of the Recents component for the current user. For secondary users, this can 80190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * be called remotely from the system user. 81190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 82cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggipublic class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener { 83190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 84190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private final static String TAG = "RecentsImpl"; 85b61e654b9a46e79827355104760a3ac5228380bcWinson 866b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The minimum amount of time between each recents button press that we will handle 876b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson private final static int MIN_TOGGLE_DELAY_MS = 350; 88b61e654b9a46e79827355104760a3ac5228380bcWinson 896b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // The duration within which the user releasing the alt tab (from when they pressed alt tab) 906b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // that the fast alt-tab animation will run. If the user's alt-tab takes longer than this 916b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // duration, then we will toggle recents after this duration. 926b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson private final static int FAST_ALT_TAB_DELAY_MS = 225; 93190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 94190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public final static String RECENTS_PACKAGE = "com.android.systemui"; 95190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity"; 96e693aafe0511c2a7ffc571b22abeefba44046225Winson 97190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 98938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim * An implementation of TaskStackListener, that allows us to listen for changes to the system 99190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * task stacks and update recents accordingly. 100190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 101938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim class TaskStackListenerImpl extends TaskStackListener { 102190fe3bf88388fcb109af64571e3baa0d01f1c37Winson @Override 103190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onTaskStackChanged() { 104938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim // Preloads the next task 105a0fdeec66caa4d70786c7f6f31f79a24eef9da10Jorim Jaggi RecentsConfiguration config = Recents.getConfiguration(); 106190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) { 107e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 108e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 109190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask(); 110190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 111190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Load the next task only if we aren't svelte 112190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 11365c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 114190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 115190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // This callback is made when a new activity is launched and the old one is paused 116190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // so ignore the current activity and try and preload the thumbnail for the 117190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // previous one. 118190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTaskInfo != null) { 119190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.runningTaskId = runningTaskInfo.id; 120190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 121190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTasks = 2; 122190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTaskThumbnails = 2; 123190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 124190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadPausedActivities = true; 125190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.loadTasks(mContext, plan, launchOpts); 126190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 127190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 128190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 129190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 1304bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected static RecentsTaskLoadPlan sInstanceLoadPlan; 131190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 1324bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected Context mContext; 1334bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected Handler mHandler; 134190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStackListenerImpl mTaskStackListener; 135190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsAppWidgetHost mAppWidgetHost; 1364bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected boolean mCanReuseTaskStackViews = true; 137dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean mDraggingInRecents; 138e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi boolean mLaunchedWhileDocking; 139190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 140190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Task launching 141190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mSearchBarBounds = new Rect(); 142190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mTaskStackBounds = new Rect(); 143190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect mLastTaskViewBounds = new Rect(); 144190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskViewTransform mTmpTransform = new TaskViewTransform(); 145190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mStatusBarHeight; 146190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mNavBarHeight; 147190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mNavBarWidth; 148190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int mTaskBarHeight; 149190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 150190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Header (for transition) 151190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskViewHeader mHeaderBar; 152190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final Object mHeaderBarLock = new Object(); 1534bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected TaskStackView mDummyStackView; 154190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 155190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Variables to keep track of if we need to start recents after binding 1564bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected boolean mTriggeredFromAltTab; 1574bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected long mLastToggleTime; 1586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson DozeTrigger mFastAltTabTrigger = new DozeTrigger(FAST_ALT_TAB_DELAY_MS, new Runnable() { 1596b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson @Override 1606b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson public void run() { 1616b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // When this fires, then the user has not released alt-tab for at least 1626b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // FAST_ALT_TAB_DELAY_MS milliseconds 163435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi showRecents(mTriggeredFromAltTab, false /* draggingInRecents */, true /* animate */, 164435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi false /* reloadTasks */); 1656b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 1666b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson }); 167190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 1684bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected Bitmap mThumbnailTransitionBitmapCache; 169190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task mThumbnailTransitionBitmapCacheKey; 170190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 171190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public RecentsImpl(Context context) { 172190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext = context; 173190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHandler = new Handler(); 1741b58561f66a9453754b1b419296899fdc08b4c93Winson mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID); 175190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 176ab84fc56114c0963c6f701de9725f5413ab76da9Winson // Initialize the static foreground thread 177ab84fc56114c0963c6f701de9725f5413ab76da9Winson ForegroundThread.get(); 178ab84fc56114c0963c6f701de9725f5413ab76da9Winson 179190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Register the task stack listener 180938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim mTaskStackListener = new TaskStackListenerImpl(); 181e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 182e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.registerTaskStackListener(mTaskStackListener); 183190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 184190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Initialize the static configuration resources 185b94443d876d3c9575e88078d0e537bb385f79ca4Winson reloadHeaderBarLayout(); 186b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 187190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 188190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // When we start, preload the data associated with the previous recent tasks. 189190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // We can use a new plan since the caches will be the same. 190e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 191190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 19265c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 193190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 194296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung launchOpts.numVisibleTasks = loader.getIconCacheSize(); 195190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize(); 196190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 197190fe3bf88388fcb109af64571e3baa0d01f1c37Winson loader.loadTasks(mContext, plan, launchOpts); 198190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 199190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 200190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onBootCompleted() { 201b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 202190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 203190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 204190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onConfigurationChanged() { 205b94443d876d3c9575e88078d0e537bb385f79ca4Winson reloadHeaderBarLayout(); 206b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); 207190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Don't reuse task stack views if the configuration changes 208190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mCanReuseTaskStackViews = false; 20953ec42cb17693b2d631746e1e5d31021a3359163Winson Recents.getConfiguration().updateOnConfigurationChange(); 210190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 211190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 212190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 213190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * This is only called from the system user's Recents. Secondary users will instead proxy their 214190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * visibility change events through to the system user via 215190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}. 216190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 217190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onVisibilityChanged(Context context, boolean visible) { 218190fe3bf88388fcb109af64571e3baa0d01f1c37Winson SystemUIApplication app = (SystemUIApplication) context; 219190fe3bf88388fcb109af64571e3baa0d01f1c37Winson PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); 220190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (statusBar != null) { 221190fe3bf88388fcb109af64571e3baa0d01f1c37Winson statusBar.updateRecentsVisibility(visible); 222190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 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(ScreenPinningRequestEvent)}. 229190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 230190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void onStartScreenPinning(Context context) { 231190fe3bf88388fcb109af64571e3baa0d01f1c37Winson SystemUIApplication app = (SystemUIApplication) context; 232190fe3bf88388fcb109af64571e3baa0d01f1c37Winson PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); 233190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (statusBar != null) { 234190fe3bf88388fcb109af64571e3baa0d01f1c37Winson statusBar.showScreenPinningRequest(false); 235190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 236190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 237190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 238bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, 239e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi boolean animate, boolean launchedWhileDockingTask) { 240190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTriggeredFromAltTab = triggeredFromAltTab; 241dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDraggingInRecents = draggingInRecents; 242e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi mLaunchedWhileDocking = launchedWhileDockingTask; 243e693aafe0511c2a7ffc571b22abeefba44046225Winson if (mFastAltTabTrigger.isAsleep()) { 244e693aafe0511c2a7ffc571b22abeefba44046225Winson // Fast alt-tab duration has elapsed, fall through to showing Recents and reset 245e693aafe0511c2a7ffc571b22abeefba44046225Winson mFastAltTabTrigger.stopDozing(); 2466b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } else if (mFastAltTabTrigger.isDozing()) { 247e693aafe0511c2a7ffc571b22abeefba44046225Winson // Fast alt-tab duration has not elapsed. If this is triggered by a different 248e693aafe0511c2a7ffc571b22abeefba44046225Winson // showRecents() call, then ignore that call for now. 249e693aafe0511c2a7ffc571b22abeefba44046225Winson // TODO: We can not handle quick tabs that happen between the initial showRecents() call 250e693aafe0511c2a7ffc571b22abeefba44046225Winson // that started the activity and the activity starting up. The severity of this 251e693aafe0511c2a7ffc571b22abeefba44046225Winson // is inversely proportional to the FAST_ALT_TAB_DELAY_MS duration though. 2526b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (!triggeredFromAltTab) { 2536b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 2546b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 2556b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson mFastAltTabTrigger.stopDozing(); 256e693aafe0511c2a7ffc571b22abeefba44046225Winson } else if (triggeredFromAltTab) { 257e693aafe0511c2a7ffc571b22abeefba44046225Winson // The fast alt-tab detector is not yet running, so start the trigger and wait for the 258e693aafe0511c2a7ffc571b22abeefba44046225Winson // hideRecents() call, or for the fast alt-tab duration to elapse 259e693aafe0511c2a7ffc571b22abeefba44046225Winson mFastAltTabTrigger.startDozing(); 260e693aafe0511c2a7ffc571b22abeefba44046225Winson return; 2616b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 262190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 263190fe3bf88388fcb109af64571e3baa0d01f1c37Winson try { 264190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Check if the top task is in the home stack, and start the recents activity 265e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 266e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 267190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean isTopTaskHome = new MutableBoolean(true); 268e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) { 269bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, isTopTaskHome.value, animate); 270190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 271190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } catch (ActivityNotFoundException e) { 2721b58561f66a9453754b1b419296899fdc08b4c93Winson Log.e(TAG, "Failed to launch RecentsActivity", e); 273190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 274190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 275190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 276190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 2772799eca21715390faf10596884b65165528f89c4Winson if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) { 2782799eca21715390faf10596884b65165528f89c4Winson // The user has released alt-tab before the trigger has run, so just show the next 2792799eca21715390faf10596884b65165528f89c4Winson // task immediately 2802799eca21715390faf10596884b65165528f89c4Winson showNextTask(); 2816b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 2822799eca21715390faf10596884b65165528f89c4Winson // Cancel the fast alt-tab trigger 2832799eca21715390faf10596884b65165528f89c4Winson mFastAltTabTrigger.stopDozing(); 2842799eca21715390faf10596884b65165528f89c4Winson return; 285190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 2862799eca21715390faf10596884b65165528f89c4Winson 2872799eca21715390faf10596884b65165528f89c4Winson // Defer to the activity to handle hiding recents, if it handles it, then it must still 2882799eca21715390faf10596884b65165528f89c4Winson // be visible 2892799eca21715390faf10596884b65165528f89c4Winson EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab, 2902799eca21715390faf10596884b65165528f89c4Winson triggeredFromHomeKey)); 291190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 292190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 293190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void toggleRecents() { 2946b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Skip this toggle if we are already waiting to trigger recents via alt-tab 2956b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (mFastAltTabTrigger.isDozing()) { 2966b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 2976b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 2986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 299dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDraggingInRecents = false; 300e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi mLaunchedWhileDocking = false; 301190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mTriggeredFromAltTab = false; 302190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 303190fe3bf88388fcb109af64571e3baa0d01f1c37Winson try { 304e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 305e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 306190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean isTopTaskHome = new MutableBoolean(true); 307b61e654b9a46e79827355104760a3ac5228380bcWinson long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime; 308b61e654b9a46e79827355104760a3ac5228380bcWinson 309e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { 310e693aafe0511c2a7ffc571b22abeefba44046225Winson RecentsDebugFlags debugFlags = Recents.getDebugFlags(); 3115da4347b41b105dc6c6c01bf2810af3ce3013229Winson RecentsConfiguration config = Recents.getConfiguration(); 3125da4347b41b105dc6c6c01bf2810af3ce3013229Winson RecentsActivityLaunchState launchState = config.getLaunchState(); 313ead5c0fc20e5c60a68cd017af0b8eacaf1167a1cWinson Chung if (!launchState.launchedWithAltTab) { 314b61e654b9a46e79827355104760a3ac5228380bcWinson // If the user taps quickly 315e693aafe0511c2a7ffc571b22abeefba44046225Winson if (!debugFlags.isPagingEnabled() || 316e693aafe0511c2a7ffc571b22abeefba44046225Winson (ViewConfiguration.getDoubleTapMinTime() < elapsedTime && 317e693aafe0511c2a7ffc571b22abeefba44046225Winson elapsedTime < ViewConfiguration.getDoubleTapTimeout())) { 318b61e654b9a46e79827355104760a3ac5228380bcWinson // Launch the next focused task 319b61e654b9a46e79827355104760a3ac5228380bcWinson EventBus.getDefault().post(new LaunchNextTaskRequestEvent()); 320b61e654b9a46e79827355104760a3ac5228380bcWinson } else { 321b61e654b9a46e79827355104760a3ac5228380bcWinson // Notify recents to move onto the next task 322b61e654b9a46e79827355104760a3ac5228380bcWinson EventBus.getDefault().post(new IterateRecentsEvent()); 323b61e654b9a46e79827355104760a3ac5228380bcWinson } 3240d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } else { 3250d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // If the user has toggled it too quickly, then just eat up the event here (it's 3260d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // better than showing a janky screenshot). 3270d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // NOTE: Ideally, the screenshot mechanism would take the window transform into 3280d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // account 329b61e654b9a46e79827355104760a3ac5228380bcWinson if (elapsedTime < MIN_TOGGLE_DELAY_MS) { 3300d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson return; 3310d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 3320d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson 3330d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson EventBus.getDefault().post(new ToggleRecentsEvent()); 3340d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson mLastToggleTime = SystemClock.elapsedRealtime(); 3350d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 336190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return; 337190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 3380d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // If the user has toggled it too quickly, then just eat up the event here (it's 3390d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // better than showing a janky screenshot). 3400d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // NOTE: Ideally, the screenshot mechanism would take the window transform into 3410d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson // account 342b61e654b9a46e79827355104760a3ac5228380bcWinson if (elapsedTime < MIN_TOGGLE_DELAY_MS) { 3430d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson return; 3440d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson } 3450d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson 346190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Otherwise, start the recents activity 347bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */); 348d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson 349d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson // Only close the other system windows if we are actually showing recents 350d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS); 3510d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson mLastToggleTime = SystemClock.elapsedRealtime(); 352190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 353190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } catch (ActivityNotFoundException e) { 3541b58561f66a9453754b1b419296899fdc08b4c93Winson Log.e(TAG, "Failed to launch RecentsActivity", e); 355190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 356190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 357190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 358190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void preloadRecents() { 359190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Preload only the raw task list into a new load plan (which will be consumed by the 360190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // RecentsActivity) only if there is a task to animate to. 361e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 362e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); 363190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MutableBoolean topTaskHome = new MutableBoolean(true); 364e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) { 3655b4e0d2b11b2b3579bac36fde5ac3805346618ccWinson RecentsTaskLoader loader = Recents.getTaskLoader(); 3665b4e0d2b11b2b3579bac36fde5ac3805346618ccWinson sInstanceLoadPlan = loader.createLoadPlan(mContext); 367190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan.preloadRawTasks(topTaskHome.value); 36865c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value); 369190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack = sInstanceLoadPlan.getTaskStack(); 3704b057c6787624b75613769a857ccdf51114bb7f2Winson if (stack.getTaskCount() > 0) { 371ab84fc56114c0963c6f701de9725f5413ab76da9Winson // We try and draw the thumbnail transition bitmap in parallel before 372ab84fc56114c0963c6f701de9725f5413ab76da9Winson // toggle/show recents is called 373190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView); 374190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 375190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 376190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 377190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 378190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void cancelPreloadingRecents() { 379190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Do nothing 380190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 381190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 382dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void onDraggingInRecents(float distanceFromTop) { 383dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop)); 384dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 385dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 386dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void onDraggingInRecentsEnded(float velocity) { 387dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity)); 388dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 389dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 3906b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson /** 3916b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson * Transitions to the next recent task in the stack. 3926b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson */ 3936b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson public void showNextTask() { 3946b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson SystemServicesProxy ssp = Recents.getSystemServices(); 3956b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson RecentsTaskLoader loader = Recents.getTaskLoader(); 3966b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 39765c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 3986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson TaskStack focusedStack = plan.getTaskStack(); 3996b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4006b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there are no tasks in the focused stack 4014b057c6787624b75613769a857ccdf51114bb7f2Winson if (focusedStack == null || focusedStack.getTaskCount() == 0) return; 4026b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4036b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask(); 4046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there is no running task 4056b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (runningTask == null) return; 4066b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4076b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Find the task in the recents list 408e86deb8adb022ba7721a1af1112d3a45e757095cWinson boolean isTopTaskHome = SystemServicesProxy.isHomeStack(runningTask.stackId); 409250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = focusedStack.getStackTasks(); 4106b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson Task toTask = null; 4116b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityOptions launchOpts = null; 4126b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson int taskCount = tasks.size(); 4136b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson for (int i = taskCount - 1; i >= 1; i--) { 4146b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson Task task = tasks.get(i); 415e86deb8adb022ba7721a1af1112d3a45e757095cWinson if (isTopTaskHome) { 416e86deb8adb022ba7721a1af1112d3a45e757095cWinson toTask = tasks.get(i - 1); 417e86deb8adb022ba7721a1af1112d3a45e757095cWinson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 418e86deb8adb022ba7721a1af1112d3a45e757095cWinson R.anim.recents_launch_next_affiliated_task_target, 419e86deb8adb022ba7721a1af1112d3a45e757095cWinson R.anim.recents_fast_toggle_app_home_exit); 420e86deb8adb022ba7721a1af1112d3a45e757095cWinson break; 421e86deb8adb022ba7721a1af1112d3a45e757095cWinson } else if (task.key.id == runningTask.id) { 4226b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson toTask = tasks.get(i - 1); 4236b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 4246b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_target, 4256b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_source); 4266b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson break; 4276b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4286b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4296b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4306b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Return early if there is no next task 4316b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson if (toTask == null) { 4326b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ssp.startInPlaceAnimationOnFrontMostApplication( 4336b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson ActivityOptions.makeCustomInPlaceAnimation(mContext, 4346b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson R.anim.recents_launch_prev_affiliated_task_bounce)); 4356b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson return; 4366b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4376b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4386b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson // Launch the task 439296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts); 4406b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson } 4416b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson 4426b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson /** 4436b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson * Transitions to the next affiliated task. 4446b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson */ 445190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showRelativeAffiliatedTask(boolean showNextTask) { 446e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 447e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 448190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); 44965c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(plan, -1, true /* isTopTaskHome */); 450190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack focusedStack = plan.getTaskStack(); 451190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 452190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there are no tasks in the focused stack 4534b057c6787624b75613769a857ccdf51114bb7f2Winson if (focusedStack == null || focusedStack.getTaskCount() == 0) return; 454190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 455e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask(); 456190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there is no running task (can't determine affiliated tasks in this case) 457190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (runningTask == null) return; 458190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if the running task is in the home stack (optimization) 4595510f6c1b9c20483e1507147eed7b24ac8bb6363Winson if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return; 460190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 461190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Find the task in the recents list 462250608a5cd08862f4752a924d51710805850db8aWinson ArrayList<Task> tasks = focusedStack.getStackTasks(); 463190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task toTask = null; 464190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions launchOpts = null; 465190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskCount = tasks.size(); 466190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int numAffiliatedTasks = 0; 467190fe3bf88388fcb109af64571e3baa0d01f1c37Winson for (int i = 0; i < taskCount; i++) { 468190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task task = tasks.get(i); 469190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (task.key.id == runningTask.id) { 470190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskGrouping group = task.group; 471190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Task.TaskKey toTaskKey; 472190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (showNextTask) { 473190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTaskKey = group.getNextTaskInGroup(task); 474190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 475190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_target, 476190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_source); 477190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 478190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTaskKey = group.getPrevTaskInGroup(task); 479190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts = ActivityOptions.makeCustomAnimation(mContext, 480190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_target, 481190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_source); 482190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 483190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTaskKey != null) { 484190fe3bf88388fcb109af64571e3baa0d01f1c37Winson toTask = focusedStack.findTaskWithId(toTaskKey.id); 485190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 486190fe3bf88388fcb109af64571e3baa0d01f1c37Winson numAffiliatedTasks = group.getTaskCount(); 487190fe3bf88388fcb109af64571e3baa0d01f1c37Winson break; 488190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 489190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 490190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 491190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Return early if there is no next task 492190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTask == null) { 493190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (numAffiliatedTasks > 1) { 494190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (showNextTask) { 495e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.startInPlaceAnimationOnFrontMostApplication( 496190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions.makeCustomInPlaceAnimation(mContext, 497190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_next_affiliated_task_bounce)); 498190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 499e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ssp.startInPlaceAnimationOnFrontMostApplication( 500190fe3bf88388fcb109af64571e3baa0d01f1c37Winson ActivityOptions.makeCustomInPlaceAnimation(mContext, 501190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_launch_prev_affiliated_task_bounce)); 502190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 503190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 504190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return; 505190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 506190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 507190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of actually launched affiliated tasks 508190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1); 509190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 510190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Launch the task 511296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts); 512190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 513190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 514190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showNextAffiliatedTask() { 515190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of when the affiliated task is triggered 516190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_next", 1); 517190fe3bf88388fcb109af64571e3baa0d01f1c37Winson showRelativeAffiliatedTask(true); 518190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 519190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 520190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public void showPrevAffiliatedTask() { 521190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Keep track of when the affiliated task is triggered 522190fe3bf88388fcb109af64571e3baa0d01f1c37Winson MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1); 523190fe3bf88388fcb109af64571e3baa0d01f1c37Winson showRelativeAffiliatedTask(false); 524190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 525190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 526cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi public void dockTopTask(int topTaskId, int dragMode, 527cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi int stackCreateMode, Rect initialBounds) { 52875b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi SystemServicesProxy ssp = Recents.getSystemServices(); 5299511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi 5309511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi // Make sure we inform DividerView before we actually start the activity so we can change 5319511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi // the resize mode already. 532e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) { 533899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds)); 534e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang showRecents( 535e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang false /* triggeredFromAltTab */, 536e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, 537e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang false /* animate */, 538e693aafe0511c2a7ffc571b22abeefba44046225Winson true /* launchedWhileDockingTask*/); 539e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang } 54075b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi } 54175b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi 542190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 543190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Returns the preloaded load plan and invalidates it. 544190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 545190fe3bf88388fcb109af64571e3baa0d01f1c37Winson public static RecentsTaskLoadPlan consumeInstanceLoadPlan() { 546190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan plan = sInstanceLoadPlan; 547190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = null; 548190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return plan; 549190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 550190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 551190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 552b94443d876d3c9575e88078d0e537bb385f79ca4Winson * Reloads all the layouts for the header bar transition. 553b94443d876d3c9575e88078d0e537bb385f79ca4Winson */ 554b94443d876d3c9575e88078d0e537bb385f79ca4Winson private void reloadHeaderBarLayout() { 555b94443d876d3c9575e88078d0e537bb385f79ca4Winson Resources res = mContext.getResources(); 556b94443d876d3c9575e88078d0e537bb385f79ca4Winson LayoutInflater inflater = LayoutInflater.from(mContext); 557b94443d876d3c9575e88078d0e537bb385f79ca4Winson 558b94443d876d3c9575e88078d0e537bb385f79ca4Winson mStatusBarHeight = res.getDimensionPixelSize( 559b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.status_bar_height); 560b94443d876d3c9575e88078d0e537bb385f79ca4Winson mNavBarHeight = res.getDimensionPixelSize( 561b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.navigation_bar_height); 562b94443d876d3c9575e88078d0e537bb385f79ca4Winson mNavBarWidth = res.getDimensionPixelSize( 563b94443d876d3c9575e88078d0e537bb385f79ca4Winson com.android.internal.R.dimen.navigation_bar_width); 564b94443d876d3c9575e88078d0e537bb385f79ca4Winson mTaskBarHeight = res.getDimensionPixelSize( 565b94443d876d3c9575e88078d0e537bb385f79ca4Winson R.dimen.recents_task_bar_height); 5668873754f66527d2cc9feab295dd4eef23298212aWinson mDummyStackView = new TaskStackView(mContext); 567b94443d876d3c9575e88078d0e537bb385f79ca4Winson mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, 568b94443d876d3c9575e88078d0e537bb385f79ca4Winson null, false); 569b94443d876d3c9575e88078d0e537bb385f79ca4Winson } 570b94443d876d3c9575e88078d0e537bb385f79ca4Winson 571b94443d876d3c9575e88078d0e537bb385f79ca4Winson /** 572190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Prepares the header bar layout for the next transition, if the task view bounds has changed 573190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * since the last call, it will attempt to re-measure and layout the header bar to the new size. 574190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * 575190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one 576190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * is not already bound (can be expensive) 577f0d1c44a59a10707baa0cca8dd377302260710c1Winson * @param stack the stack to initialize the stack layout with 578190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 5798873754f66527d2cc9feab295dd4eef23298212aWinson private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) { 58053ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 581e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 582c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect systemInsets = new Rect(); 583c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi ssp.getStableInsets(systemInsets); 584e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Rect windowRect = ssp.getWindowRect(); 585c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi calculateWindowStableInsets(systemInsets, windowRect); 586c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi windowRect.offsetTo(0, 0); 587190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 588190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the configuration for the current state 589c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi config.update(systemInsets); 590190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 591d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) { 592190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Try and pre-emptively bind the search widget on startup to ensure that we 593190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // have the right thumbnail bounds to animate to. 594190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Note: We have to reload the widget id before we get the task stack bounds below 595e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) { 59653ec42cb17693b2d631746e1e5d31021a3359163Winson config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds); 597190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 598190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 59953ec42cb17693b2d631746e1e5d31021a3359163Winson config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right, 600190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mSearchBarBounds, mTaskStackBounds); 601190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 602190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Rebind the header bar and draw it for the transition 6038873754f66527d2cc9feab295dd4eef23298212aWinson TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm(); 604190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Rect taskStackBounds = new Rect(mTaskStackBounds); 6058873754f66527d2cc9feab295dd4eef23298212aWinson stackLayout.setSystemInsets(systemInsets); 606f0d1c44a59a10707baa0cca8dd377302260710c1Winson if (stack != null) { 6078873754f66527d2cc9feab295dd4eef23298212aWinson stackLayout.initialize(taskStackBounds, 608f0d1c44a59a10707baa0cca8dd377302260710c1Winson TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack)); 6094cfea695112f2f61d9f4391e6d928561a68a7db3Winson mDummyStackView.setTasks(stack, false /* notifyStackChanges */, 6104cfea695112f2f61d9f4391e6d928561a68a7db3Winson false /* relayoutTaskStack */); 611f0d1c44a59a10707baa0cca8dd377302260710c1Winson } 6128873754f66527d2cc9feab295dd4eef23298212aWinson Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds(); 613190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (!taskViewBounds.equals(mLastTaskViewBounds)) { 614190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mLastTaskViewBounds.set(taskViewBounds); 615190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 616190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int taskViewWidth = taskViewBounds.width(); 617190fe3bf88388fcb109af64571e3baa0d01f1c37Winson synchronized (mHeaderBarLock) { 618190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.measure( 619190fe3bf88388fcb109af64571e3baa0d01f1c37Winson View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY), 620190fe3bf88388fcb109af64571e3baa0d01f1c37Winson View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY)); 621190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight); 622190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 623190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 624190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 625190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 626190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 627c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi * Given the stable insets and the rect for our window, calculates the insets that affect our 628c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi * window. 629c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi */ 630c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi private void calculateWindowStableInsets(Rect inOutInsets, Rect windowRect) { 631c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect displayRect = Recents.getSystemServices().getDisplayRect(); 632c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi 633c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi // Display rect without insets - available app space 634c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect appRect = new Rect(displayRect); 635c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi appRect.inset(inOutInsets); 636c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi 637c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi // Our window intersected with available app space 638c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi Rect windowRectWithInsets = new Rect(windowRect); 639c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi windowRectWithInsets.intersect(appRect); 640c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.left = windowRectWithInsets.left - windowRect.left; 641c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.top = windowRectWithInsets.top - windowRect.top; 642c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.right = windowRect.right - windowRectWithInsets.right; 643c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi inOutInsets.bottom = windowRect.bottom - windowRectWithInsets.bottom; 644c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi } 645c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi 646c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi /** 647190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Preloads the icon of a task. 648190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 649190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void preloadIcon(ActivityManager.RunningTaskInfo task) { 650190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Ensure that we load the running task's icon 651190fe3bf88388fcb109af64571e3baa0d01f1c37Winson RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); 652190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.runningTaskId = task.id; 653190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.loadThumbnails = false; 654190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchOpts.onlyLoadForCache = true; 655e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts); 656190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 657190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 658190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 659190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Caches the header thumbnail used for a window animation asynchronously into 660190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * {@link #mThumbnailTransitionBitmapCache}. 661190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 662190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask, 663190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack, TaskStackView stackView) { 664190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preloadIcon(topTask); 665190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 666190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the header bar if necessary 667b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); 668190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 669190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the destination rect 670190fe3bf88388fcb109af64571e3baa0d01f1c37Winson final Task toTask = new Task(); 671e693aafe0511c2a7ffc571b22abeefba44046225Winson final TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask); 6723fb67562c548662910160d5672b1b9558bd6571cWinson ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() { 673190fe3bf88388fcb109af64571e3baa0d01f1c37Winson @Override 674ab84fc56114c0963c6f701de9725f5413ab76da9Winson public void run() { 675ab84fc56114c0963c6f701de9725f5413ab76da9Winson final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform); 676ab84fc56114c0963c6f701de9725f5413ab76da9Winson mHandler.post(new Runnable() { 677ab84fc56114c0963c6f701de9725f5413ab76da9Winson @Override 678ab84fc56114c0963c6f701de9725f5413ab76da9Winson public void run() { 679ab84fc56114c0963c6f701de9725f5413ab76da9Winson mThumbnailTransitionBitmapCache = transitionBitmap; 680ab84fc56114c0963c6f701de9725f5413ab76da9Winson mThumbnailTransitionBitmapCacheKey = toTask; 681ab84fc56114c0963c6f701de9725f5413ab76da9Winson } 682ab84fc56114c0963c6f701de9725f5413ab76da9Winson }); 683190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 684ab84fc56114c0963c6f701de9725f5413ab76da9Winson }); 685190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 686190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 687190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 688190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for a unknown state->recents transition. 689190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 6904bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected ActivityOptions getUnknownTransitionActivityOptions() { 691190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 692190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_unknown_enter, 693190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_unknown_exit, 6943fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 695190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 696190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 697190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 698190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for a home->recents transition. 699190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 7004bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) { 701190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (fromSearchHome) { 702190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 703190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_search_launcher_enter, 704190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_search_launcher_exit, 7053fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 706190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 707190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return ActivityOptions.makeCustomAnimation(mContext, 708190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_launcher_enter, 709190fe3bf88388fcb109af64571e3baa0d01f1c37Winson R.anim.recents_from_launcher_exit, 7103fb67562c548662910160d5672b1b9558bd6571cWinson mHandler, null); 711190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 712190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 713190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 714190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Creates the activity options for an app->recents transition. 715190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 716190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private ActivityOptions getThumbnailTransitionActivityOptions( 717e693aafe0511c2a7ffc571b22abeefba44046225Winson ActivityManager.RunningTaskInfo topTask, TaskStackView stackView) { 718d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) { 719d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>(); 720e693aafe0511c2a7ffc571b22abeefba44046225Winson ArrayList<Task> tasks = stackView.getStack().getStackTasks(); 721e693aafe0511c2a7ffc571b22abeefba44046225Winson TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm(); 722e693aafe0511c2a7ffc571b22abeefba44046225Winson TaskStackViewScroller stackScroller = stackView.getScroller(); 723e693aafe0511c2a7ffc571b22abeefba44046225Winson 724003eda6c230a1b1c4e3709466c46660e7602d740Winson stackView.updateLayoutAlgorithm(true /* boundScroll */); 725e693aafe0511c2a7ffc571b22abeefba44046225Winson stackView.updateToInitialState(); 726e693aafe0511c2a7ffc571b22abeefba44046225Winson 727d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski for (int i = tasks.size() - 1; i >= 0; i--) { 728d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Task task = tasks.get(i); 729387aac6ad7bde21f2c2510cb8a2f3af3959721e0Winson if (task.isFreeformTask()) { 730e693aafe0511c2a7ffc571b22abeefba44046225Winson mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task, 731e693aafe0511c2a7ffc571b22abeefba44046225Winson stackScroller.getStackScroll(), mTmpTransform, null); 732d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Rect toTaskRect = new Rect(); 733d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski mTmpTransform.rect.round(toTaskRect); 734d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform); 735d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect)); 736d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 737d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 738d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()]; 739d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski specs.toArray(specsArray); 740d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, 7413fb67562c548662910160d5672b1b9558bd6571cWinson specsArray, mHandler, null, this); 742d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } else { 743d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski // Update the destination rect 744d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Task toTask = new Task(); 745e693aafe0511c2a7ffc571b22abeefba44046225Winson TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask); 746d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski RectF toTaskRect = toTransform.rect; 747d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform); 748d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski if (thumbnail != null) { 749d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, 750d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski thumbnail, (int) toTaskRect.left, (int) toTaskRect.top, 7513fb67562c548662910160d5672b1b9558bd6571cWinson (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null); 752d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 753d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski // If both the screenshot and thumbnail fails, then just fall back to the default transition 754d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return getUnknownTransitionActivityOptions(); 755d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 756d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski } 757190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 758d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask, 759d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski TaskViewTransform toTransform) { 760190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap thumbnail; 761190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (mThumbnailTransitionBitmapCacheKey != null 762190fe3bf88388fcb109af64571e3baa0d01f1c37Winson && mThumbnailTransitionBitmapCacheKey.key != null 763190fe3bf88388fcb109af64571e3baa0d01f1c37Winson && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) { 764190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = mThumbnailTransitionBitmapCache; 765190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mThumbnailTransitionBitmapCacheKey = null; 766190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mThumbnailTransitionBitmapCache = null; 767190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 768190fe3bf88388fcb109af64571e3baa0d01f1c37Winson preloadIcon(topTask); 769190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform); 770190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 771d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski return thumbnail; 772190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 773190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 774190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 775190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Returns the transition rect for the given task id. 776190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 777e693aafe0511c2a7ffc571b22abeefba44046225Winson private TaskViewTransform getThumbnailTransitionTransform(TaskStackView stackView, 778e693aafe0511c2a7ffc571b22abeefba44046225Winson Task runningTaskOut) { 779190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Find the running task in the TaskStack 780e693aafe0511c2a7ffc571b22abeefba44046225Winson TaskStack stack = stackView.getStack(); 78165c851e6e9e08656744b6f66d3da188e3283b17dWinson Task launchTask = stack.getLaunchTarget(); 78265c851e6e9e08656744b6f66d3da188e3283b17dWinson if (launchTask != null) { 78365c851e6e9e08656744b6f66d3da188e3283b17dWinson runningTaskOut.copyFrom(launchTask); 78465c851e6e9e08656744b6f66d3da188e3283b17dWinson } else { 785190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // If no task is specified or we can not find the task just use the front most one 78635a8b04140598a5b5c4865254b942adb6a830991Winson launchTask = stack.getStackFrontMostTask(true /* includeFreeform */); 78765c851e6e9e08656744b6f66d3da188e3283b17dWinson runningTaskOut.copyFrom(launchTask); 788190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 789190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 790190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Get the transform for the running task 791003eda6c230a1b1c4e3709466c46660e7602d740Winson stackView.updateLayoutAlgorithm(true /* boundScroll */); 792e693aafe0511c2a7ffc571b22abeefba44046225Winson stackView.updateToInitialState(); 793c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask, 794190fe3bf88388fcb109af64571e3baa0d01f1c37Winson stackView.getScroller().getStackScroll(), mTmpTransform, null); 795190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return mTmpTransform; 796190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 797190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 798190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 799190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Draws the header of a task used for the window animation into a bitmap. 800190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 801190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) { 8028be1634a543022bd6ee0c1e974d3201d452981e8Winson SystemServicesProxy ssp = Recents.getSystemServices(); 803190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (toTransform != null && toTask.key != null) { 804190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap thumbnail; 805190fe3bf88388fcb109af64571e3baa0d01f1c37Winson synchronized (mHeaderBarLock) { 806509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung int toHeaderWidth = (int) toTransform.rect.width(); 807190fe3bf88388fcb109af64571e3baa0d01f1c37Winson int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); 8088be1634a543022bd6ee0c1e974d3201d452981e8Winson boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode(); 809509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(), 810509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung (int) toTransform.rect.height()); 811190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, 812190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Bitmap.Config.ARGB_8888); 813c742f973b1e506732911c156c5869fd377afc5bfWinson if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { 814190fe3bf88388fcb109af64571e3baa0d01f1c37Winson thumbnail.eraseColor(0xFFff0000); 815190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 816190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Canvas c = new Canvas(thumbnail); 817190fe3bf88388fcb109af64571e3baa0d01f1c37Winson c.scale(toTransform.scale, toTransform.scale); 8188be1634a543022bd6ee0c1e974d3201d452981e8Winson mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */, 8198be1634a543022bd6ee0c1e974d3201d452981e8Winson disabledInSafeMode); 820e693aafe0511c2a7ffc571b22abeefba44046225Winson mHeaderBar.setDimAlpha(toTransform.dimAlpha); 821190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mHeaderBar.draw(c); 822190fe3bf88388fcb109af64571e3baa0d01f1c37Winson c.setBitmap(null); 823190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 824190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 825190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return thumbnail.createAshmemBitmap(); 826190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 827190fe3bf88388fcb109af64571e3baa0d01f1c37Winson return null; 828190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 829190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 830190fe3bf88388fcb109af64571e3baa0d01f1c37Winson /** 831190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Shows the recents activity 832190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 8334bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, 834bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi boolean isTopTaskHome, boolean animate) { 835e7f138c7f0a190c86cec10fb32fa106aacae4093Winson RecentsTaskLoader loader = Recents.getTaskLoader(); 836190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 837e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we 838435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi // should always preload the tasks now. If we are dragging in recents, reload them as 839435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi // the stacks might have changed. 840e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi if (mLaunchedWhileDocking || mTriggeredFromAltTab ||sInstanceLoadPlan == null) { 841e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson // Create a new load plan if preloadRecents() was never triggered 842190fe3bf88388fcb109af64571e3baa0d01f1c37Winson sInstanceLoadPlan = loader.createLoadPlan(mContext); 843190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 844e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) { 84565c851e6e9e08656744b6f66d3da188e3283b17dWinson loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome); 846190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 847190fe3bf88388fcb109af64571e3baa0d01f1c37Winson TaskStack stack = sInstanceLoadPlan.getTaskStack(); 848190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 849f0d1c44a59a10707baa0cca8dd377302260710c1Winson // Update the header bar if necessary 850b94443d876d3c9575e88078d0e537bb385f79ca4Winson updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); 851f0d1c44a59a10707baa0cca8dd377302260710c1Winson 852190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Prepare the dummy stack for the transition 85336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson TaskStackLayoutAlgorithm.VisibilityReport stackVr = 854190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mDummyStackView.computeStackVisibilityReport(); 855bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi 856bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi if (!animate) { 857bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1); 858bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi startRecentsActivity(topTask, opts, false /* fromHome */, 859bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi false /* fromSearchHome */, false /* fromThumbnail*/, stackVr); 860bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi return; 861bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi } 862bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi 8634b057c6787624b75613769a857ccdf51114bb7f2Winson boolean hasRecentTasks = stack.getTaskCount() > 0; 864190fe3bf88388fcb109af64571e3baa0d01f1c37Winson boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks; 865190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 866190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (useThumbnailTransition) { 867190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Try starting with a thumbnail transition 868e693aafe0511c2a7ffc571b22abeefba44046225Winson ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView); 869190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (opts != null) { 870190fe3bf88388fcb109af64571e3baa0d01f1c37Winson startRecentsActivity(topTask, opts, false /* fromHome */, 871190fe3bf88388fcb109af64571e3baa0d01f1c37Winson false /* fromSearchHome */, true /* fromThumbnail */, stackVr); 872190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 873190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Fall through below to the non-thumbnail transition 874fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan useThumbnailTransition = false; 875fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 876fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 877fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan 878fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan if (!useThumbnailTransition) { 879fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan // If there is no thumbnail transition, but is launching from home into recents, then 880fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan // use a quick home transition and do the animation from home 881fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan if (hasRecentTasks) { 882fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan SystemServicesProxy ssp = Recents.getSystemServices(); 883fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan String homeActivityPackage = ssp.getHomeActivityPackageName(); 884fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan String searchWidgetPackage = null; 885fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan if (RecentsDebugFlags.Static.EnableSearchBar) { 886fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan searchWidgetPackage = Prefs.getString(mContext, 887fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null); 888fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } else { 889fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget(); 890fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan if (searchWidgetInfo != null) { 891fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan searchWidgetPackage = searchWidgetInfo.provider.getPackageName(); 892fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 893fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 894fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan 895fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan // Determine whether we are coming from a search owned home activity 896fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan boolean fromSearchHome = (homeActivityPackage != null) && 897fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan homeActivityPackage.equals(searchWidgetPackage); 898fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome); 899fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome, 900fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan false /* fromThumbnail */, stackVr); 901fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } else { 902fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan // Otherwise we do the normal fade from an unknown source 903fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan ActivityOptions opts = getUnknownTransitionActivityOptions(); 904fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan startRecentsActivity(topTask, opts, true /* fromHome */, 905fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan false /* fromSearchHome */, false /* fromThumbnail */, stackVr); 906fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 907fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 908fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan mLastToggleTime = SystemClock.elapsedRealtime(); 909fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan } 910fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan 911fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan /** 912190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Starts the recents activity. 913190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */ 914190fe3bf88388fcb109af64571e3baa0d01f1c37Winson private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, 915e693aafe0511c2a7ffc571b22abeefba44046225Winson ActivityOptions opts, boolean fromHome, boolean fromSearchHome, 916e693aafe0511c2a7ffc571b22abeefba44046225Winson boolean fromThumbnail, TaskStackLayoutAlgorithm.VisibilityReport vr) { 917190fe3bf88388fcb109af64571e3baa0d01f1c37Winson // Update the configuration based on the launch options 91853ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 91953ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsActivityLaunchState launchState = config.getLaunchState(); 920190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromHome = fromSearchHome || fromHome; 921190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedFromSearchHome = fromSearchHome; 922e693aafe0511c2a7ffc571b22abeefba44046225Winson launchState.launchedFromApp = fromThumbnail || mLaunchedWhileDocking; 923e693aafe0511c2a7ffc571b22abeefba44046225Winson launchState.launchedFromAppDocked = mLaunchedWhileDocking; 924190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1; 925190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedWithAltTab = mTriggeredFromAltTab; 926190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews; 927190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedNumVisibleTasks = vr.numVisibleTasks; 928190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails; 929190fe3bf88388fcb109af64571e3baa0d01f1c37Winson launchState.launchedHasConfigurationChanged = false; 930b1e71d09f24be2c18120146eaae1ffd9444feb9aWinson launchState.launchedViaDragGesture = mDraggingInRecents; 931e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi launchState.launchedWhileDocking = mLaunchedWhileDocking; 932190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 933190fe3bf88388fcb109af64571e3baa0d01f1c37Winson Intent intent = new Intent(); 9344bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY); 935190fe3bf88388fcb109af64571e3baa0d01f1c37Winson intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 936190fe3bf88388fcb109af64571e3baa0d01f1c37Winson | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 937190fe3bf88388fcb109af64571e3baa0d01f1c37Winson | Intent.FLAG_ACTIVITY_TASK_ON_HOME); 938b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan 939190fe3bf88388fcb109af64571e3baa0d01f1c37Winson if (opts != null) { 940190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT); 941190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } else { 942190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mContext.startActivityAsUser(intent, UserHandle.CURRENT); 943190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 944190fe3bf88388fcb109af64571e3baa0d01f1c37Winson mCanReuseTaskStackViews = true; 945cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi EventBus.getDefault().send(new RecentsActivityStartingEvent()); 946190fe3bf88388fcb109af64571e3baa0d01f1c37Winson } 947190fe3bf88388fcb109af64571e3baa0d01f1c37Winson 9483fb67562c548662910160d5672b1b9558bd6571cWinson /**** OnAnimationFinishedListener Implementation ****/ 9491a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski 9501a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski @Override 9511a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski public void onAnimationFinished() { 9521a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent()); 9531a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski } 954190fe3bf88388fcb109af64571e3baa0d01f1c37Winson} 955