RecentsImpl.java revision b1e71d09f24be2c18120146eaae1ffd9444feb9a
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;
22190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.ActivityNotFoundException;
23190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Context;
24190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Intent;
25190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.res.Resources;
26190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Bitmap;
27190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Canvas;
28190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Rect;
293150e574e6e903a17193e0b90433d69c0e20ae4cWinsonimport android.graphics.RectF;
30190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.Handler;
31190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.SystemClock;
32190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.UserHandle;
331b58561f66a9453754b1b419296899fdc08b4c93Winsonimport android.util.Log;
34190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.util.MutableBoolean;
35d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynskiimport android.view.AppTransitionAnimationSpec;
36190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.LayoutInflater;
37190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.View;
38030979c1e4ad269efa747eb3c03a4b0e3d820f55Jorim Jaggi
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;
64190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.statusbar.phone.PhoneStatusBar;
65190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
66190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport java.util.ArrayList;
67190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
681b58561f66a9453754b1b419296899fdc08b4c93Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
691b58561f66a9453754b1b419296899fdc08b4c93Winson
70190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/**
71190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of the Recents component for the current user.  For secondary users, this can
72190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * be called remotely from the system user.
73190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */
741a4dfe593aafda057ac9cb3086b84588d88cd09fFilip Gruszczynskipublic class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
751a4dfe593aafda057ac9cb3086b84588d88cd09fFilip Gruszczynski        ActivityOptions.OnAnimationFinishedListener {
76190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
77190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private final static String TAG = "RecentsImpl";
78ab84fc56114c0963c6f701de9725f5413ab76da9Winson    private final static boolean DEBUG = false;
79190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
806b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // The minimum amount of time between each recents button press that we will handle
816b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    private final static int MIN_TOGGLE_DELAY_MS = 350;
826b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // The duration within which the user releasing the alt tab (from when they pressed alt tab)
836b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // that the fast alt-tab animation will run.  If the user's alt-tab takes longer than this
846b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // duration, then we will toggle recents after this duration.
856b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    private final static int FAST_ALT_TAB_DELAY_MS = 225;
86190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
87190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public final static String RECENTS_PACKAGE = "com.android.systemui";
88190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
89190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
90190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
91190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
92190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * task stacks and update recents accordingly.
93190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
94190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
95190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Handler mHandler;
96190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
97190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public TaskStackListenerImpl(Handler handler) {
98190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mHandler = handler;
99190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
100190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
101190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        @Override
102190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public void onTaskStackChanged() {
103190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Debounce any task stack changes
104190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mHandler.removeCallbacks(this);
105190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mHandler.post(this);
106190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
107190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
108190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        /** Preloads the next task */
109190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public void run() {
110190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // TODO: Temporarily skip this if multi stack is enabled
111190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            /*
112190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            RecentsConfiguration config = RecentsConfiguration.getInstance();
113190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
114e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                RecentsTaskLoader loader = Recents.getTaskLoader();
115e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                SystemServicesProxy ssp = Recents.getSystemServices();
116190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
117190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
118190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Load the next task only if we aren't svelte
119190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
120190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                loader.preloadTasks(plan, true);
121190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
122190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // This callback is made when a new activity is launched and the old one is paused
123190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // so ignore the current activity and try and preload the thumbnail for the
124190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // previous one.
125190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (runningTaskInfo != null) {
126190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts.runningTaskId = runningTaskInfo.id;
127190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
128190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.numVisibleTasks = 2;
129190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.numVisibleTaskThumbnails = 2;
130190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.onlyLoadForCache = true;
131190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.onlyLoadPausedActivities = true;
132190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                loader.loadTasks(mContext, plan, launchOpts);
133190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
134190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            */
135190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
136190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
137190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
138e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    private static RecentsTaskLoadPlan sInstanceLoadPlan;
139190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
140190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Context mContext;
141190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Handler mHandler;
142190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskStackListenerImpl mTaskStackListener;
143190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    RecentsAppWidgetHost mAppWidgetHost;
144190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mBootCompleted;
145190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mCanReuseTaskStackViews = true;
146dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    boolean mDraggingInRecents;
147190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
148190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Task launching
149190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mSearchBarBounds = new Rect();
150190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mTaskStackBounds = new Rect();
151190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mLastTaskViewBounds = new Rect();
152190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskViewTransform mTmpTransform = new TaskViewTransform();
153190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mStatusBarHeight;
154190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mNavBarHeight;
155190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mNavBarWidth;
156190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mTaskBarHeight;
157190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
158190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Header (for transition)
159190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskViewHeader mHeaderBar;
160190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    final Object mHeaderBarLock = new Object();
161190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskStackView mDummyStackView;
162190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
163190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Variables to keep track of if we need to start recents after binding
164190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mTriggeredFromAltTab;
165190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    long mLastToggleTime;
1666b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    DozeTrigger mFastAltTabTrigger = new DozeTrigger(FAST_ALT_TAB_DELAY_MS, new Runnable() {
1676b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        @Override
1686b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        public void run() {
1696b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // When this fires, then the user has not released alt-tab for at least
1706b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // FAST_ALT_TAB_DELAY_MS milliseconds
171bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            showRecents(mTriggeredFromAltTab, false /* draggingInRecents */, true /* animate */);
1726b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
1736b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    });
174190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
175190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Bitmap mThumbnailTransitionBitmapCache;
176190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Task mThumbnailTransitionBitmapCacheKey;
177190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
178190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public RecentsImpl(Context context) {
179190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mContext = context;
180190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mHandler = new Handler();
1811b58561f66a9453754b1b419296899fdc08b4c93Winson        mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID);
182190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Resources res = mContext.getResources();
183190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        LayoutInflater inflater = LayoutInflater.from(mContext);
184190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
185ab84fc56114c0963c6f701de9725f5413ab76da9Winson        // Initialize the static foreground thread
186ab84fc56114c0963c6f701de9725f5413ab76da9Winson        ForegroundThread.get();
187ab84fc56114c0963c6f701de9725f5413ab76da9Winson
188190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Register the task stack listener
189190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTaskStackListener = new TaskStackListenerImpl(mHandler);
190e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
191e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ssp.registerTaskStackListener(mTaskStackListener);
192190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
193190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Initialize the static configuration resources
194190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
195190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
196190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
197190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
198190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mDummyStackView = new TaskStackView(mContext, new TaskStack());
199190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
200190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                null, false);
201190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
202190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
203190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // When we start, preload the data associated with the previous recent tasks.
204190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // We can use a new plan since the caches will be the same.
205e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
206190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
207190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.preloadTasks(plan, true /* isTopTaskHome */);
208190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
209190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
210190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
211190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.onlyLoadForCache = true;
212190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.loadTasks(mContext, plan, launchOpts);
213190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
214190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
215190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onBootCompleted() {
216190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mBootCompleted = true;
217190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
218190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
219190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
220190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
221190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onConfigurationChanged() {
222190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Don't reuse task stack views if the configuration changes
223190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mCanReuseTaskStackViews = false;
22453ec42cb17693b2d631746e1e5d31021a3359163Winson        Recents.getConfiguration().updateOnConfigurationChange();
225190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
226190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
227190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
228190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * This is only called from the system user's Recents.  Secondary users will instead proxy their
229190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * visibility change events through to the system user via
230190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
231190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
232190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onVisibilityChanged(Context context, boolean visible) {
233190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        SystemUIApplication app = (SystemUIApplication) context;
234190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
235190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (statusBar != null) {
236190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            statusBar.updateRecentsVisibility(visible);
237190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
238190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
239190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
240190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
241190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * This is only called from the system user's Recents.  Secondary users will instead proxy their
242190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * visibility change events through to the system user via
243190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}.
244190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
245190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onStartScreenPinning(Context context) {
246190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        SystemUIApplication app = (SystemUIApplication) context;
247190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
248190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (statusBar != null) {
249190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            statusBar.showScreenPinningRequest(false);
250190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
251190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
252190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
253190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
254bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi    public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents,
255bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            boolean animate) {
256190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTriggeredFromAltTab = triggeredFromAltTab;
257dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        mDraggingInRecents = draggingInRecents;
2586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (mFastAltTabTrigger.hasTriggered()) {
2596b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // We are calling this from the doze trigger, so just fall through to show Recents
2606b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            mFastAltTabTrigger.resetTrigger();
2616b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        } else if (mFastAltTabTrigger.isDozing()) {
2626b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // We are dozing but haven't yet triggered, ignore this if this is not another alt-tab,
2636b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // otherwise, this is an additional tab (alt-tab*), which means that we should trigger
2646b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // immediately (fall through and disable the pending trigger)
2656b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // TODO: This is tricky, we need to handle the tab key, but Recents has not yet started
2666b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            //       so we may actually additional signal to handle multiple quick tab cases.  The
2676b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            //       severity of this is inversely proportional to the FAST_ALT_TAB_DELAY_MS
2686b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            //       duration though
2696b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            if (!triggeredFromAltTab) {
2706b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                return;
2716b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            }
2726b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            mFastAltTabTrigger.stopDozing();
2736b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        } else {
2746b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // Otherwise, the doze trigger is not running, and if this is an alt tab, we should
2756b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // start the trigger and then wait for the hide (or for it to elapse)
2766b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            if (triggeredFromAltTab) {
2776b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                mFastAltTabTrigger.startDozing();
2786b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                return;
2796b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            }
2806b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
281190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
282190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        try {
283190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Check if the top task is in the home stack, and start the recents activity
284e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            SystemServicesProxy ssp = Recents.getSystemServices();
285e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
286190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            MutableBoolean isTopTaskHome = new MutableBoolean(true);
287e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
288bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi                startRecentsActivity(topTask, isTopTaskHome.value, animate);
289190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
290190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } catch (ActivityNotFoundException e) {
2911b58561f66a9453754b1b419296899fdc08b4c93Winson            Log.e(TAG, "Failed to launch RecentsActivity", e);
292190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
293190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
294190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
295190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
296190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
297190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (mBootCompleted) {
2986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
2996b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                // The user has released alt-tab before the trigger has run, so just show the next
3006b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                // task immediately
3016b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                showNextTask();
3026b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
3036b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                // Cancel the fast alt-tab trigger
3046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                mFastAltTabTrigger.stopDozing();
3056b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                mFastAltTabTrigger.resetTrigger();
3066b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                return;
3076b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            }
3086b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
309190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Defer to the activity to handle hiding recents, if it handles it, then it must still
310190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // be visible
311e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
312412e18058dc2cd5779d2451fce7fd74631f9e237Winson                    triggeredFromHomeKey));
313190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
314190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
315190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
316190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
317190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void toggleRecents() {
3186b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Skip this toggle if we are already waiting to trigger recents via alt-tab
3196b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (mFastAltTabTrigger.isDozing()) {
3206b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            return;
3216b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
3226b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
323dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        mDraggingInRecents = false;
324190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTriggeredFromAltTab = false;
325190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
326190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        try {
327e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            SystemServicesProxy ssp = Recents.getSystemServices();
328e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
329190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            MutableBoolean isTopTaskHome = new MutableBoolean(true);
330e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
3315da4347b41b105dc6c6c01bf2810af3ce3013229Winson                RecentsConfiguration config = Recents.getConfiguration();
3325da4347b41b105dc6c6c01bf2810af3ce3013229Winson                RecentsActivityLaunchState launchState = config.getLaunchState();
333c742f973b1e506732911c156c5869fd377afc5bfWinson                RecentsDebugFlags flags = Recents.getDebugFlags();
3348b1871d74137d7e36ba0fed5608772f51f62015bWinson                if (flags.isPageOnToggleEnabled() && !launchState.launchedWithAltTab) {
3350d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    // Notify recents to move onto the next task
3360d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    EventBus.getDefault().post(new IterateRecentsEvent());
3370d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                } 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
3426b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                    if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) {
3430d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                        return;
3440d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    }
3450d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson
3460d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    EventBus.getDefault().post(new ToggleRecentsEvent());
3470d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    mLastToggleTime = SystemClock.elapsedRealtime();
3480d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                }
349190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                return;
350190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
3510d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // If the user has toggled it too quickly, then just eat up the event here (it's
3520d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // better than showing a janky screenshot).
3530d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // NOTE: Ideally, the screenshot mechanism would take the window transform into
3540d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // account
3556b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) {
3560d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    return;
3570d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                }
3580d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson
359190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Otherwise, start the recents activity
360bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi                startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */);
3610d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                mLastToggleTime = SystemClock.elapsedRealtime();
362190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
363190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } catch (ActivityNotFoundException e) {
3641b58561f66a9453754b1b419296899fdc08b4c93Winson            Log.e(TAG, "Failed to launch RecentsActivity", e);
365190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
366190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
367190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
368190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
369190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void preloadRecents() {
370190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Preload only the raw task list into a new load plan (which will be consumed by the
371190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // RecentsActivity) only if there is a task to animate to.
372e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
373e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
374190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MutableBoolean topTaskHome = new MutableBoolean(true);
375e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
376190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        sInstanceLoadPlan = loader.createLoadPlan(mContext);
377e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
378190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
379190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
380190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStack stack = sInstanceLoadPlan.getTaskStack();
381190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (stack.getTaskCount() > 0) {
382ab84fc56114c0963c6f701de9725f5413ab76da9Winson                // We try and draw the thumbnail transition bitmap in parallel before
383ab84fc56114c0963c6f701de9725f5413ab76da9Winson                // toggle/show recents is called
384190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView);
385190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
386190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
387190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
388190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
389190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
390190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void cancelPreloadingRecents() {
391190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Do nothing
392190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
393190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
394dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    @Override
395dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    public void onDraggingInRecents(float distanceFromTop) {
396dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop));
397dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    }
398dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi
399dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    @Override
400dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    public void onDraggingInRecentsEnded(float velocity) {
401dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
402dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    }
403dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi
4046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    /**
4056b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     * Transitions to the next recent task in the stack.
4066b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     */
4076b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    public void showNextTask() {
4086b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        SystemServicesProxy ssp = Recents.getSystemServices();
4096b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        RecentsTaskLoader loader = Recents.getTaskLoader();
4106b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
4116b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        loader.preloadTasks(plan, true /* isTopTaskHome */);
4126b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        TaskStack focusedStack = plan.getTaskStack();
4136b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4146b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Return early if there are no tasks in the focused stack
4156b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
4166b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4176b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
4186b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Return early if there is no running task
4196b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (runningTask == null) return;
4206b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4216b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Find the task in the recents list
422e86deb8adb022ba7721a1af1112d3a45e757095cWinson        boolean isTopTaskHome = SystemServicesProxy.isHomeStack(runningTask.stackId);
4236b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        ArrayList<Task> tasks = focusedStack.getTasks();
4246b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        Task toTask = null;
4256b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        ActivityOptions launchOpts = null;
4266b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        int taskCount = tasks.size();
4276b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        for (int i = taskCount - 1; i >= 1; i--) {
4286b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            Task task = tasks.get(i);
429e86deb8adb022ba7721a1af1112d3a45e757095cWinson            if (isTopTaskHome) {
430e86deb8adb022ba7721a1af1112d3a45e757095cWinson                toTask = tasks.get(i - 1);
431e86deb8adb022ba7721a1af1112d3a45e757095cWinson                launchOpts = ActivityOptions.makeCustomAnimation(mContext,
432e86deb8adb022ba7721a1af1112d3a45e757095cWinson                        R.anim.recents_launch_next_affiliated_task_target,
433e86deb8adb022ba7721a1af1112d3a45e757095cWinson                        R.anim.recents_fast_toggle_app_home_exit);
434e86deb8adb022ba7721a1af1112d3a45e757095cWinson                break;
435e86deb8adb022ba7721a1af1112d3a45e757095cWinson            } else if (task.key.id == runningTask.id) {
4366b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                toTask = tasks.get(i - 1);
4376b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                launchOpts = ActivityOptions.makeCustomAnimation(mContext,
4386b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                        R.anim.recents_launch_prev_affiliated_task_target,
4396b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                        R.anim.recents_launch_prev_affiliated_task_source);
4406b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                break;
4416b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            }
4426b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
4436b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4446b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Return early if there is no next task
4456b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (toTask == null) {
4466b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            ssp.startInPlaceAnimationOnFrontMostApplication(
4476b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                    ActivityOptions.makeCustomInPlaceAnimation(mContext,
4486b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                            R.anim.recents_launch_prev_affiliated_task_bounce));
4496b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            return;
4506b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
4516b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4526b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Launch the task
4536b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
4546b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    }
4556b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4566b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    /**
4576b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     * Transitions to the next affiliated task.
4586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     */
459190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showRelativeAffiliatedTask(boolean showNextTask) {
460e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
461e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
462190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
463190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.preloadTasks(plan, true /* isTopTaskHome */);
464190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStack focusedStack = plan.getTaskStack();
465190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
466190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there are no tasks in the focused stack
467190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
468190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
469e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
470190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no running task (can't determine affiliated tasks in this case)
471190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (runningTask == null) return;
472190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if the running task is in the home stack (optimization)
4735510f6c1b9c20483e1507147eed7b24ac8bb6363Winson        if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return;
474190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
475190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Find the task in the recents list
476190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ArrayList<Task> tasks = focusedStack.getTasks();
477190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Task toTask = null;
478190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ActivityOptions launchOpts = null;
479190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        int taskCount = tasks.size();
480190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        int numAffiliatedTasks = 0;
481190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        for (int i = 0; i < taskCount; i++) {
482190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Task task = tasks.get(i);
483190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (task.key.id == runningTask.id) {
484190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                TaskGrouping group = task.group;
485190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                Task.TaskKey toTaskKey;
486190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (showNextTask) {
487190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTaskKey = group.getNextTaskInGroup(task);
488190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
489190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_next_affiliated_task_target,
490190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_next_affiliated_task_source);
491190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
492190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTaskKey = group.getPrevTaskInGroup(task);
493190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
494190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_prev_affiliated_task_target,
495190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_prev_affiliated_task_source);
496190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
497190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (toTaskKey != null) {
498190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTask = focusedStack.findTaskWithId(toTaskKey.id);
499190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
500190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                numAffiliatedTasks = group.getTaskCount();
501190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                break;
502190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
503190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
504190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
505190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no next task
506190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTask == null) {
507190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (numAffiliatedTasks > 1) {
508190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (showNextTask) {
509e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    ssp.startInPlaceAnimationOnFrontMostApplication(
510190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
511190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                                    R.anim.recents_launch_next_affiliated_task_bounce));
512190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
513e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    ssp.startInPlaceAnimationOnFrontMostApplication(
514190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
515190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                                    R.anim.recents_launch_prev_affiliated_task_bounce));
516190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
517190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
518190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return;
519190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
520190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
521190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of actually launched affiliated tasks
522190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
523190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
524190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Launch the task
52583c1b07a99a6ddd80c30cfc101f3de037a0d215dWinson        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
526190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
527190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
528190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showNextAffiliatedTask() {
529190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of when the affiliated task is triggered
530190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_next", 1);
531190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        showRelativeAffiliatedTask(true);
532190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
533190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
534190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showPrevAffiliatedTask() {
535190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of when the affiliated task is triggered
536190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1);
537190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        showRelativeAffiliatedTask(false);
538190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
539190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
540dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    public void dockTopTask(boolean draggingInRecents) {
54175b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi        SystemServicesProxy ssp = Recents.getSystemServices();
54275b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
54338c96cb83446009458558c438b066e38eacab0f2Winson        if (topTask != null && !SystemServicesProxy.isHomeStack(topTask.stackId)) {
544030979c1e4ad269efa747eb3c03a4b0e3d820f55Jorim Jaggi            ssp.moveTaskToDockedStack(topTask.id,
54575b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi                    ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
546bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            showRecents(false /* triggeredFromAltTab */, draggingInRecents, false /* animate */);
54775b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi        }
54875b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi    }
54975b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi
550190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
551190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Returns the preloaded load plan and invalidates it.
552190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
553190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
554190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = sInstanceLoadPlan;
555190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        sInstanceLoadPlan = null;
556190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return plan;
557190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
558190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
559190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
560190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Prepares the header bar layout for the next transition, if the task view bounds has changed
561190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * since the last call, it will attempt to re-measure and layout the header bar to the new size.
562190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     *
563190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
564190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     *                               is not already bound (can be expensive)
565190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
566190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
56753ec42cb17693b2d631746e1e5d31021a3359163Winson        RecentsConfiguration config = Recents.getConfiguration();
568e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
569e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        Rect windowRect = ssp.getWindowRect();
570190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
571190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the configuration for the current state
57253ec42cb17693b2d631746e1e5d31021a3359163Winson        config.update(mContext, ssp, ssp.getWindowRect());
573190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
574c742f973b1e506732911c156c5869fd377afc5bfWinson        if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) {
575190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Try and pre-emptively bind the search widget on startup to ensure that we
576190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // have the right thumbnail bounds to animate to.
577190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Note: We have to reload the widget id before we get the task stack bounds below
578e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
57953ec42cb17693b2d631746e1e5d31021a3359163Winson                config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds);
580190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
581190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
582190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Rect systemInsets = new Rect(0, mStatusBarHeight,
58353ec42cb17693b2d631746e1e5d31021a3359163Winson                (config.hasTransposedNavBar ? mNavBarWidth : 0),
58453ec42cb17693b2d631746e1e5d31021a3359163Winson                (config.hasTransposedNavBar ? 0 : mNavBarHeight));
58553ec42cb17693b2d631746e1e5d31021a3359163Winson        config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
586190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mSearchBarBounds, mTaskStackBounds);
587190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
588190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Rebind the header bar and draw it for the transition
58936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
590190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Rect taskStackBounds = new Rect(mTaskStackBounds);
591190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        algo.setSystemInsets(systemInsets);
59236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        algo.initialize(taskStackBounds);
593190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
594190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (!taskViewBounds.equals(mLastTaskViewBounds)) {
595190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mLastTaskViewBounds.set(taskViewBounds);
596190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
597190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            int taskViewWidth = taskViewBounds.width();
598190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            synchronized (mHeaderBarLock) {
599190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mHeaderBar.measure(
600190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
601190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
602190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
603190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
604190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
605190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
606190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
607190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
608190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Preloads the icon of a task.
609190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
610190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void preloadIcon(ActivityManager.RunningTaskInfo task) {
611190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Ensure that we load the running task's icon
612190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
613190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.runningTaskId = task.id;
614190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.loadThumbnails = false;
615190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.onlyLoadForCache = true;
616e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
617190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
618190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
619190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
620190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Caches the header thumbnail used for a window animation asynchronously into
621190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link #mThumbnailTransitionBitmapCache}.
622190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
623190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
624190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStack stack, TaskStackView stackView) {
625190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        preloadIcon(topTask);
626190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
627190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the header bar if necessary
628190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
629190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
630190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the destination rect
631eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        mDummyStackView.updateLayoutForStack(stack);
632190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        final Task toTask = new Task();
633190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
634190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                topTask.id, toTask);
6353fb67562c548662910160d5672b1b9558bd6571cWinson        ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() {
636190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            @Override
637ab84fc56114c0963c6f701de9725f5413ab76da9Winson            public void run() {
638ab84fc56114c0963c6f701de9725f5413ab76da9Winson                final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform);
639ab84fc56114c0963c6f701de9725f5413ab76da9Winson                mHandler.post(new Runnable() {
640ab84fc56114c0963c6f701de9725f5413ab76da9Winson                    @Override
641ab84fc56114c0963c6f701de9725f5413ab76da9Winson                    public void run() {
642ab84fc56114c0963c6f701de9725f5413ab76da9Winson                        mThumbnailTransitionBitmapCache = transitionBitmap;
643ab84fc56114c0963c6f701de9725f5413ab76da9Winson                        mThumbnailTransitionBitmapCacheKey = toTask;
644ab84fc56114c0963c6f701de9725f5413ab76da9Winson                    }
645ab84fc56114c0963c6f701de9725f5413ab76da9Winson                });
646190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
647ab84fc56114c0963c6f701de9725f5413ab76da9Winson        });
648190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
649190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
650190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
651190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for a unknown state->recents transition.
652190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
653190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getUnknownTransitionActivityOptions() {
654190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return ActivityOptions.makeCustomAnimation(mContext,
655190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_unknown_enter,
656190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_unknown_exit,
6573fb67562c548662910160d5672b1b9558bd6571cWinson                mHandler, null);
658190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
659190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
660190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
661190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for a home->recents transition.
662190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
663190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
664190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (fromSearchHome) {
665190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return ActivityOptions.makeCustomAnimation(mContext,
666190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    R.anim.recents_from_search_launcher_enter,
667190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    R.anim.recents_from_search_launcher_exit,
6683fb67562c548662910160d5672b1b9558bd6571cWinson                    mHandler, null);
669190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
670190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return ActivityOptions.makeCustomAnimation(mContext,
671190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_launcher_enter,
672190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_launcher_exit,
6733fb67562c548662910160d5672b1b9558bd6571cWinson                mHandler, null);
674190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
675190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
676190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
677190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for an app->recents transition.
678190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
679190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getThumbnailTransitionActivityOptions(
680190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
681d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski        if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
682d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
683d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            stackView.getScroller().setStackScrollToInitialState();
684d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            ArrayList<Task> tasks = stack.getTasks();
685d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            for (int i = tasks.size() - 1; i >= 0; i--) {
686d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                Task task = tasks.get(i);
687d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
688d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
689d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                            stackView.getScroller().getStackScroll(), mTmpTransform, null);
690d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    Rect toTaskRect = new Rect();
691d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    mTmpTransform.rect.round(toTaskRect);
692d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
693d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
694d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                }
695d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            }
696d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
697d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            specs.toArray(specsArray);
698d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
6993fb67562c548662910160d5672b1b9558bd6571cWinson                    specsArray, mHandler, null, this);
700d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski        } else {
701d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            // Update the destination rect
702d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            Task toTask = new Task();
703d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
704d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    topTask.id, toTask);
705d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            RectF toTaskRect = toTransform.rect;
706d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
707d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            if (thumbnail != null) {
708d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
709d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                        thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
7103fb67562c548662910160d5672b1b9558bd6571cWinson                        (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null);
711d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            }
712d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            // If both the screenshot and thumbnail fails, then just fall back to the default transition
713d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            return getUnknownTransitionActivityOptions();
714d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski        }
715d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski    }
716190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
717d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski    private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
718d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            TaskViewTransform toTransform) {
719190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Bitmap thumbnail;
720190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (mThumbnailTransitionBitmapCacheKey != null
721190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                && mThumbnailTransitionBitmapCacheKey.key != null
722190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
723190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            thumbnail = mThumbnailTransitionBitmapCache;
724190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mThumbnailTransitionBitmapCacheKey = null;
725190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mThumbnailTransitionBitmapCache = null;
726190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } else {
727190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            preloadIcon(topTask);
728190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
729190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
730d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski        return thumbnail;
731190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
732190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
733190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
734190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Returns the transition rect for the given task id.
735190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
736190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
737190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStackView stackView, int runningTaskId, Task runningTaskOut) {
738190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Find the running task in the TaskStack
739190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Task task = null;
740190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ArrayList<Task> tasks = stack.getTasks();
741190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (runningTaskId != -1) {
742190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Otherwise, try and find the task with the
743190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            int taskCount = tasks.size();
744190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            for (int i = taskCount - 1; i >= 0; i--) {
745190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                Task t = tasks.get(i);
746190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (t.key.id == runningTaskId) {
747190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    task = t;
748190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    runningTaskOut.copyFrom(t);
749190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    break;
750190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
751190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
752190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
753190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (task == null) {
754190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If no task is specified or we can not find the task just use the front most one
755190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            task = tasks.get(tasks.size() - 1);
756190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            runningTaskOut.copyFrom(task);
757190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
758190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
759190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Get the transform for the running task
760190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        stackView.getScroller().setStackScrollToInitialState();
761190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
762190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                stackView.getScroller().getStackScroll(), mTmpTransform, null);
763190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return mTmpTransform;
764190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
765190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
766190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
767190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Draws the header of a task used for the window animation into a bitmap.
768190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
769190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
770190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTransform != null && toTask.key != null) {
771190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Bitmap thumbnail;
772190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            synchronized (mHeaderBarLock) {
773190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
774190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
775190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
776190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        Bitmap.Config.ARGB_8888);
777c742f973b1e506732911c156c5869fd377afc5bfWinson                if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
778190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    thumbnail.eraseColor(0xFFff0000);
779190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
780190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    Canvas c = new Canvas(thumbnail);
781190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    c.scale(toTransform.scale, toTransform.scale);
782190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mHeaderBar.rebindToTask(toTask);
783190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mHeaderBar.draw(c);
784190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    c.setBitmap(null);
785190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
786190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
787190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return thumbnail.createAshmemBitmap();
788190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
789190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return null;
790190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
791190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
792190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
793190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Shows the recents activity
794190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
795190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
796bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            boolean isTopTaskHome, boolean animate) {
797e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
798190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
799190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the header bar if necessary
800190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
801190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
802e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson        // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
803e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson        // should always preload the tasks now
804e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson        if (mTriggeredFromAltTab ||sInstanceLoadPlan == null) {
805e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson            // Create a new load plan if preloadRecents() was never triggered
806190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            sInstanceLoadPlan = loader.createLoadPlan(mContext);
807190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
808e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson        if (mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
809190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
810190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
811190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStack stack = sInstanceLoadPlan.getTaskStack();
812190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
813190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Prepare the dummy stack for the transition
814eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        mDummyStackView.updateLayoutForStack(stack);
81536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        TaskStackLayoutAlgorithm.VisibilityReport stackVr =
816190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mDummyStackView.computeStackVisibilityReport();
817bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi
818bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi        if (!animate) {
819bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
820bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            startRecentsActivity(topTask, opts, false /* fromHome */,
821bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi                    false /* fromSearchHome */, false /* fromThumbnail*/, stackVr);
822bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            return;
823bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi        }
824bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi
825190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        boolean hasRecentTasks = stack.getTaskCount() > 0;
826190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
827190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
828190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (useThumbnailTransition) {
829190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Try starting with a thumbnail transition
830190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
831190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mDummyStackView);
832190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (opts != null) {
833190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, opts, false /* fromHome */,
834190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
835190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
836190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Fall through below to the non-thumbnail transition
837190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                useThumbnailTransition = false;
838190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
839190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
840190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
841190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (!useThumbnailTransition) {
842190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If there is no thumbnail transition, but is launching from home into recents, then
843190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // use a quick home transition and do the animation from home
844c742f973b1e506732911c156c5869fd377afc5bfWinson            if (!RecentsDebugFlags.Static.DisableSearchBar && hasRecentTasks) {
8455da4347b41b105dc6c6c01bf2810af3ce3013229Winson                SystemServicesProxy ssp = Recents.getSystemServices();
846e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String homeActivityPackage = ssp.getHomeActivityPackageName();
847e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String searchWidgetPackage = Prefs.getString(mContext,
848c742f973b1e506732911c156c5869fd377afc5bfWinson                        Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
849190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
850190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Determine whether we are coming from a search owned home activity
851190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                boolean fromSearchHome = (homeActivityPackage != null) &&
852190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        homeActivityPackage.equals(searchWidgetPackage);
853190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
854190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
855190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        false /* fromThumbnail */, stackVr);
856190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
857190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Otherwise we do the normal fade from an unknown source
858190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                ActivityOptions opts = getUnknownTransitionActivityOptions();
859190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, opts, true /* fromHome */,
860190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
861190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
862190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
863190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mLastToggleTime = SystemClock.elapsedRealtime();
864190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
865190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
866190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
867190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Starts the recents activity.
868190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
869190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
870190fe3bf88388fcb109af64571e3baa0d01f1c37Winson              ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
87136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson              TaskStackLayoutAlgorithm.VisibilityReport vr) {
872190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the configuration based on the launch options
87353ec42cb17693b2d631746e1e5d31021a3359163Winson        RecentsConfiguration config = Recents.getConfiguration();
87453ec42cb17693b2d631746e1e5d31021a3359163Winson        RecentsActivityLaunchState launchState = config.getLaunchState();
875190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedFromHome = fromSearchHome || fromHome;
876190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedFromSearchHome = fromSearchHome;
877190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedFromAppWithThumbnail = fromThumbnail;
878190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
879190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedWithAltTab = mTriggeredFromAltTab;
880190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
881190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
882190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
883190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedHasConfigurationChanged = false;
884b1e71d09f24be2c18120146eaae1ffd9444feb9aWinson        launchState.launchedViaDragGesture = mDraggingInRecents;
885190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
886190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Intent intent = new Intent();
887190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
888190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
889190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
890190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
891190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (opts != null) {
892190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
893190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } else {
894190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
895190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
896190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mCanReuseTaskStackViews = true;
897190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
898190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
8993fb67562c548662910160d5672b1b9558bd6571cWinson    /**** OnAnimationFinishedListener Implementation ****/
9001a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski
9011a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski    @Override
9021a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski    public void onAnimationFinished() {
9031a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski        EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent());
9041a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski    }
905190fe3bf88388fcb109af64571e3baa0d01f1c37Winson}
906