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