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