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;
2094bc4f2238d8eefb77c63a560aa0de1335ee57abWinsonimport static android.view.View.MeasureSpec;
21e693aafe0511c2a7ffc571b22abeefba44046225Winson
22190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityManager;
23190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityOptions;
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;
3222574afa00b7e32b7c4c5a1b98deebd67751b364Winsonimport android.graphics.drawable.Drawable;
33190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.Handler;
34190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.SystemClock;
35190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.UserHandle;
361b58561f66a9453754b1b419296899fdc08b4c93Winsonimport android.util.Log;
37190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.util.MutableBoolean;
38d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynskiimport android.view.AppTransitionAnimationSpec;
39190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.LayoutInflater;
40b61e654b9a46e79827355104760a3ac5228380bcWinsonimport android.view.ViewConfiguration;
41db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggiimport android.view.WindowManager;
42c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson
43675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinsonimport android.widget.Toast;
44190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.internal.logging.MetricsLogger;
45db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggiimport com.android.internal.policy.DockedDividerUtils;
46190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.R;
47190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.SystemUIApplication;
48412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.EventBus;
49899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggiimport com.android.systemui.recents.events.activity.DockedTopTaskEvent;
501b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
51412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.HideRecentsEvent;
520d14d4da91c3d8b1221269712d5abf43a7cf9f31Winsonimport com.android.systemui.recents.events.activity.IterateRecentsEvent;
53b61e654b9a46e79827355104760a3ac5228380bcWinsonimport com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
54cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggiimport com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
55412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.ToggleRecentsEvent;
56190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
57190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
58dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
59dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
606b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinsonimport com.android.systemui.recents.misc.DozeTrigger;
61ab84fc56114c0963c6f701de9725f5413ab76da9Winsonimport com.android.systemui.recents.misc.ForegroundThread;
62190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.misc.SystemServicesProxy;
63938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kimimport com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
64190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoadPlan;
65190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoader;
66190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.Task;
67190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskGrouping;
68190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskStack;
6936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winsonimport com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
701b58561f66a9453754b1b419296899fdc08b4c93Winsonimport com.android.systemui.recents.views.TaskStackView;
71e693aafe0511c2a7ffc571b22abeefba44046225Winsonimport com.android.systemui.recents.views.TaskStackViewScroller;
72190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewHeader;
73190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewTransform;
74db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggiimport com.android.systemui.stackdivider.DividerView;
75d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winsonimport com.android.systemui.statusbar.BaseStatusBar;
76cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggiimport com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
77190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.statusbar.phone.PhoneStatusBar;
78190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
79190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport java.util.ArrayList;
80190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
81190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/**
82190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of the Recents component for the current user.  For secondary users, this can
83190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * be called remotely from the system user.
84190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */
85cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggipublic class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener {
86190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
87190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private final static String TAG = "RecentsImpl";
88b61e654b9a46e79827355104760a3ac5228380bcWinson
896b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // The minimum amount of time between each recents button press that we will handle
906b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    private final static int MIN_TOGGLE_DELAY_MS = 350;
91b61e654b9a46e79827355104760a3ac5228380bcWinson
926b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // The duration within which the user releasing the alt tab (from when they pressed alt tab)
936b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // that the fast alt-tab animation will run.  If the user's alt-tab takes longer than this
946b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    // duration, then we will toggle recents after this duration.
956b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    private final static int FAST_ALT_TAB_DELAY_MS = 225;
96190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
97190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public final static String RECENTS_PACKAGE = "com.android.systemui";
98190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
99e693aafe0511c2a7ffc571b22abeefba44046225Winson
100190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
101938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim     * An implementation of TaskStackListener, that allows us to listen for changes to the system
102190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * task stacks and update recents accordingly.
103190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
104938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim    class TaskStackListenerImpl extends TaskStackListener {
105190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        @Override
106190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public void onTaskStackChanged() {
107938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim            // Preloads the next task
108a0fdeec66caa4d70786c7f6f31f79a24eef9da10Jorim Jaggi            RecentsConfiguration config = Recents.getConfiguration();
109190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
110e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                RecentsTaskLoader loader = Recents.getTaskLoader();
111e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                SystemServicesProxy ssp = Recents.getSystemServices();
112d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
113190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
114190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Load the next task only if we aren't svelte
115190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
116dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson                loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
117190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
118190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // This callback is made when a new activity is launched and the old one is paused
119190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // so ignore the current activity and try and preload the thumbnail for the
120190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // previous one.
121190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (runningTaskInfo != null) {
122190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts.runningTaskId = runningTaskInfo.id;
123190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
124190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.numVisibleTasks = 2;
125190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.numVisibleTaskThumbnails = 2;
126190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.onlyLoadForCache = true;
127190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.onlyLoadPausedActivities = true;
128190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                loader.loadTasks(mContext, plan, launchOpts);
129190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
130190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
131190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
132190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
1334bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected static RecentsTaskLoadPlan sInstanceLoadPlan;
134190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
1354bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected Context mContext;
1364bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected Handler mHandler;
137190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskStackListenerImpl mTaskStackListener;
138dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    boolean mDraggingInRecents;
139e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi    boolean mLaunchedWhileDocking;
140190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
141190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Task launching
142190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mTaskStackBounds = new Rect();
143190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskViewTransform mTmpTransform = new TaskViewTransform();
144190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mStatusBarHeight;
145190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mNavBarHeight;
146190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mNavBarWidth;
147190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mTaskBarHeight;
148190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
149190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Header (for transition)
150190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskViewHeader mHeaderBar;
151190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    final Object mHeaderBarLock = new Object();
1524bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected TaskStackView mDummyStackView;
153190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
154190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Variables to keep track of if we need to start recents after binding
1554bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected boolean mTriggeredFromAltTab;
1564bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected long mLastToggleTime;
1576b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    DozeTrigger mFastAltTabTrigger = new DozeTrigger(FAST_ALT_TAB_DELAY_MS, new Runnable() {
1586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        @Override
1596b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        public void run() {
1606b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // When this fires, then the user has not released alt-tab for at least
1616b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            // FAST_ALT_TAB_DELAY_MS milliseconds
162435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi            showRecents(mTriggeredFromAltTab, false /* draggingInRecents */, true /* animate */,
163db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                    false /* reloadTasks */, false /* fromHome */,
164db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                    DividerView.INVALID_RECENTS_GROW_TARGET);
1656b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
1666b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    });
167190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
168aeb298c4db913b376fb6053ec30c132a93e04635Winson    protected Bitmap mThumbTransitionBitmapCache;
169190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
170190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public RecentsImpl(Context context) {
171190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mContext = context;
172190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mHandler = new Handler();
173190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
174ab84fc56114c0963c6f701de9725f5413ab76da9Winson        // Initialize the static foreground thread
175ab84fc56114c0963c6f701de9725f5413ab76da9Winson        ForegroundThread.get();
176ab84fc56114c0963c6f701de9725f5413ab76da9Winson
177190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Register the task stack listener
178938a50b424eb73ee96d34c96b5e2cbd11f733d7aJaewan Kim        mTaskStackListener = new TaskStackListenerImpl();
179e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
180e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ssp.registerTaskStackListener(mTaskStackListener);
181190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
182190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Initialize the static configuration resources
183670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        LayoutInflater inflater = LayoutInflater.from(mContext);
184670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        mDummyStackView = new TaskStackView(mContext);
185670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
186670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson                null, false);
187670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        reloadResources();
18816ef39a7f6f000af761cf2c2a3e2823a0fbd0c4cWinson    }
189190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
190501d59dcea4e48f4abf00fbe671d17290cb1e66cWinson Chung    public void onBootCompleted() {
191190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // When we start, preload the data associated with the previous recent tasks.
192190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // We can use a new plan since the caches will be the same.
193e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
194190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
195dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson        loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
196190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
197296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung        launchOpts.numVisibleTasks = loader.getIconCacheSize();
198190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
199190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.onlyLoadForCache = true;
200190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.loadTasks(mContext, plan, launchOpts);
201190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
202190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
203190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onConfigurationChanged() {
20496f78f50464a0f394802ff0709ba7276976ef275Winson        Resources res = mContext.getResources();
205670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        reloadResources();
206670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        mDummyStackView.reloadOnConfigurationChange();
20796f78f50464a0f394802ff0709ba7276976ef275Winson        // Update the header bar direction directly as it is not attached to anything and does not
20896f78f50464a0f394802ff0709ba7276976ef275Winson        // layout except in updateHeaderBarLayout()
20996f78f50464a0f394802ff0709ba7276976ef275Winson        mHeaderBar.setLayoutDirection(res.getConfiguration().getLayoutDirection());
210670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson        mHeaderBar.onConfigurationChanged();
21196f78f50464a0f394802ff0709ba7276976ef275Winson        mHeaderBar.forceLayout();
21296f78f50464a0f394802ff0709ba7276976ef275Winson        mHeaderBar.measure(
21396f78f50464a0f394802ff0709ba7276976ef275Winson                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredWidth(), MeasureSpec.EXACTLY),
21496f78f50464a0f394802ff0709ba7276976ef275Winson                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredHeight(), MeasureSpec.EXACTLY));
215190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
216190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
217190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
218190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * This is only called from the system user's Recents.  Secondary users will instead proxy their
219190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * visibility change events through to the system user via
220190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
221190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
222190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onVisibilityChanged(Context context, boolean visible) {
223ab216609f1608e61827d955fcc9fd0560bc52e4dWinson        Recents.getSystemServices().setRecentsVisibility(visible);
224190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
225190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
226190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
227190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * This is only called from the system user's Recents.  Secondary users will instead proxy their
228190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * visibility change events through to the system user via
229190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}.
230190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
2310f051f5abdb31024d862a954cc4c4716b1dde616Andrii Kulian    public void onStartScreenPinning(Context context, int taskId) {
232190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        SystemUIApplication app = (SystemUIApplication) context;
233190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
234190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (statusBar != null) {
2350f051f5abdb31024d862a954cc4c4716b1dde616Andrii Kulian            statusBar.showScreenPinningRequest(taskId, false);
236190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
237190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
238190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
239bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi    public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents,
240db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi            boolean animate, boolean launchedWhileDockingTask, boolean fromHome,
241db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi            int growTarget) {
242190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTriggeredFromAltTab = triggeredFromAltTab;
243dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        mDraggingInRecents = draggingInRecents;
244e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi        mLaunchedWhileDocking = launchedWhileDockingTask;
245e693aafe0511c2a7ffc571b22abeefba44046225Winson        if (mFastAltTabTrigger.isAsleep()) {
246e693aafe0511c2a7ffc571b22abeefba44046225Winson            // Fast alt-tab duration has elapsed, fall through to showing Recents and reset
247e693aafe0511c2a7ffc571b22abeefba44046225Winson            mFastAltTabTrigger.stopDozing();
2486b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        } else if (mFastAltTabTrigger.isDozing()) {
249e693aafe0511c2a7ffc571b22abeefba44046225Winson            // Fast alt-tab duration has not elapsed.  If this is triggered by a different
250e693aafe0511c2a7ffc571b22abeefba44046225Winson            // showRecents() call, then ignore that call for now.
251e693aafe0511c2a7ffc571b22abeefba44046225Winson            // TODO: We can not handle quick tabs that happen between the initial showRecents() call
252e693aafe0511c2a7ffc571b22abeefba44046225Winson            //       that started the activity and the activity starting up.  The severity of this
253e693aafe0511c2a7ffc571b22abeefba44046225Winson            //       is inversely proportional to the FAST_ALT_TAB_DELAY_MS duration though.
2546b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            if (!triggeredFromAltTab) {
2556b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                return;
2566b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            }
2576b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            mFastAltTabTrigger.stopDozing();
258e693aafe0511c2a7ffc571b22abeefba44046225Winson        } else if (triggeredFromAltTab) {
259e693aafe0511c2a7ffc571b22abeefba44046225Winson            // The fast alt-tab detector is not yet running, so start the trigger and wait for the
260e693aafe0511c2a7ffc571b22abeefba44046225Winson            // hideRecents() call, or for the fast alt-tab duration to elapse
261e693aafe0511c2a7ffc571b22abeefba44046225Winson            mFastAltTabTrigger.startDozing();
262e693aafe0511c2a7ffc571b22abeefba44046225Winson            return;
2636b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
264190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
265190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        try {
266190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Check if the top task is in the home stack, and start the recents activity
267e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            SystemServicesProxy ssp = Recents.getSystemServices();
268d7cb517b4ce10fa98213da18ccdb2261fb797f7cWinson            boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
269d7cb517b4ce10fa98213da18ccdb2261fb797f7cWinson            MutableBoolean isHomeStackVisible = new MutableBoolean(forceVisible);
270d7cb517b4ce10fa98213da18ccdb2261fb797f7cWinson            if (forceVisible || !ssp.isRecentsActivityVisible(isHomeStackVisible)) {
271d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
272d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                startRecentsActivity(runningTask, isHomeStackVisible.value || fromHome, animate,
273d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                        growTarget);
274190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
275190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } catch (ActivityNotFoundException e) {
2761b58561f66a9453754b1b419296899fdc08b4c93Winson            Log.e(TAG, "Failed to launch RecentsActivity", e);
277190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
278190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
279190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
280190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
2812799eca21715390faf10596884b65165528f89c4Winson        if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
2822799eca21715390faf10596884b65165528f89c4Winson            // The user has released alt-tab before the trigger has run, so just show the next
2832799eca21715390faf10596884b65165528f89c4Winson            // task immediately
2842799eca21715390faf10596884b65165528f89c4Winson            showNextTask();
2856b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
2862799eca21715390faf10596884b65165528f89c4Winson            // Cancel the fast alt-tab trigger
2872799eca21715390faf10596884b65165528f89c4Winson            mFastAltTabTrigger.stopDozing();
2882799eca21715390faf10596884b65165528f89c4Winson            return;
289190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
2902799eca21715390faf10596884b65165528f89c4Winson
2912799eca21715390faf10596884b65165528f89c4Winson        // Defer to the activity to handle hiding recents, if it handles it, then it must still
2922799eca21715390faf10596884b65165528f89c4Winson        // be visible
2932799eca21715390faf10596884b65165528f89c4Winson        EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
2942799eca21715390faf10596884b65165528f89c4Winson                triggeredFromHomeKey));
295190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
296190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
297db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi    public void toggleRecents(int growTarget) {
2986b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Skip this toggle if we are already waiting to trigger recents via alt-tab
2996b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (mFastAltTabTrigger.isDozing()) {
3006b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            return;
3016b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
3026b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
303dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        mDraggingInRecents = false;
304e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi        mLaunchedWhileDocking = false;
305190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTriggeredFromAltTab = false;
306190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
307190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        try {
308e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            SystemServicesProxy ssp = Recents.getSystemServices();
309d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            MutableBoolean isHomeStackVisible = new MutableBoolean(true);
310b61e654b9a46e79827355104760a3ac5228380bcWinson            long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
311b61e654b9a46e79827355104760a3ac5228380bcWinson
312d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
313e693aafe0511c2a7ffc571b22abeefba44046225Winson                RecentsDebugFlags debugFlags = Recents.getDebugFlags();
3145da4347b41b105dc6c6c01bf2810af3ce3013229Winson                RecentsConfiguration config = Recents.getConfiguration();
3155da4347b41b105dc6c6c01bf2810af3ce3013229Winson                RecentsActivityLaunchState launchState = config.getLaunchState();
316ead5c0fc20e5c60a68cd017af0b8eacaf1167a1cWinson Chung                if (!launchState.launchedWithAltTab) {
317b61e654b9a46e79827355104760a3ac5228380bcWinson                    // If the user taps quickly
318e693aafe0511c2a7ffc571b22abeefba44046225Winson                    if (!debugFlags.isPagingEnabled() ||
319e693aafe0511c2a7ffc571b22abeefba44046225Winson                            (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
320e693aafe0511c2a7ffc571b22abeefba44046225Winson                                    elapsedTime < ViewConfiguration.getDoubleTapTimeout())) {
321b61e654b9a46e79827355104760a3ac5228380bcWinson                        // Launch the next focused task
322b61e654b9a46e79827355104760a3ac5228380bcWinson                        EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
323b61e654b9a46e79827355104760a3ac5228380bcWinson                    } else {
324b61e654b9a46e79827355104760a3ac5228380bcWinson                        // Notify recents to move onto the next task
325b61e654b9a46e79827355104760a3ac5228380bcWinson                        EventBus.getDefault().post(new IterateRecentsEvent());
326b61e654b9a46e79827355104760a3ac5228380bcWinson                    }
3270d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                } else {
3280d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    // If the user has toggled it too quickly, then just eat up the event here (it's
3290d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    // better than showing a janky screenshot).
3300d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    // NOTE: Ideally, the screenshot mechanism would take the window transform into
3310d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    // account
332b61e654b9a46e79827355104760a3ac5228380bcWinson                    if (elapsedTime < MIN_TOGGLE_DELAY_MS) {
3330d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                        return;
3340d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    }
3350d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson
3360d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    EventBus.getDefault().post(new ToggleRecentsEvent());
3370d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    mLastToggleTime = SystemClock.elapsedRealtime();
3380d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                }
339190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                return;
340190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
3410d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // If the user has toggled it too quickly, then just eat up the event here (it's
3420d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // better than showing a janky screenshot).
3430d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // NOTE: Ideally, the screenshot mechanism would take the window transform into
3440d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                // account
345b61e654b9a46e79827355104760a3ac5228380bcWinson                if (elapsedTime < MIN_TOGGLE_DELAY_MS) {
3460d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                    return;
3470d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                }
3480d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson
349190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Otherwise, start the recents activity
350d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
351d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
352d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                        growTarget);
353d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson
354d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson                // Only close the other system windows if we are actually showing recents
355d8b1d63f96580fe961e1751e7b4f56c90c1e0a76Winson                ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
3560d14d4da91c3d8b1221269712d5abf43a7cf9f31Winson                mLastToggleTime = SystemClock.elapsedRealtime();
357190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
358190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } catch (ActivityNotFoundException e) {
3591b58561f66a9453754b1b419296899fdc08b4c93Winson            Log.e(TAG, "Failed to launch RecentsActivity", e);
360190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
361190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
362190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
363190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void preloadRecents() {
364190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Preload only the raw task list into a new load plan (which will be consumed by the
365190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // RecentsActivity) only if there is a task to animate to.
366e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
367d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson        MutableBoolean isHomeStackVisible = new MutableBoolean(true);
368d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson        if (!ssp.isRecentsActivityVisible(isHomeStackVisible)) {
369d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
3705b4e0d2b11b2b3579bac36fde5ac3805346618ccWinson            RecentsTaskLoader loader = Recents.getTaskLoader();
3715b4e0d2b11b2b3579bac36fde5ac3805346618ccWinson            sInstanceLoadPlan = loader.createLoadPlan(mContext);
372dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson            sInstanceLoadPlan.preloadRawTasks(!isHomeStackVisible.value);
373dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson            loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible.value);
374190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStack stack = sInstanceLoadPlan.getTaskStack();
3754b057c6787624b75613769a857ccdf51114bb7f2Winson            if (stack.getTaskCount() > 0) {
376aeb298c4db913b376fb6053ec30c132a93e04635Winson                // Only preload the icon (but not the thumbnail since it may not have been taken for
377aeb298c4db913b376fb6053ec30c132a93e04635Winson                // the pausing activity)
378c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson                preloadIcon(runningTask.id);
379aeb298c4db913b376fb6053ec30c132a93e04635Winson
380aeb298c4db913b376fb6053ec30c132a93e04635Winson                // At this point, we don't know anything about the stack state.  So only calculate
381aeb298c4db913b376fb6053ec30c132a93e04635Winson                // the dimensions of the thumbnail that we need for the transition into Recents, but
382aeb298c4db913b376fb6053ec30c132a93e04635Winson                // do not draw it until we construct the activity options when we start Recents
383db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                updateHeaderBarLayout(stack, null /* window rect override*/);
384190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
385190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
386190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
387190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
388190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void cancelPreloadingRecents() {
389190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Do nothing
390190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
391190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
392dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    public void onDraggingInRecents(float distanceFromTop) {
393dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop));
394dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    }
395dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi
396dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    public void onDraggingInRecentsEnded(float velocity) {
397dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi        EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
398dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi    }
399dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi
400675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson    public void onShowCurrentUserToast(int msgResId, int msgLength) {
401675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson        Toast.makeText(mContext, msgResId, msgLength).show();
402675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson    }
403675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson
4046b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    /**
4056b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     * Transitions to the next recent task in the stack.
4066b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     */
4076b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    public void showNextTask() {
4086b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        SystemServicesProxy ssp = Recents.getSystemServices();
4096b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        RecentsTaskLoader loader = Recents.getTaskLoader();
4106b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
411dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson        loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
4126b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        TaskStack focusedStack = plan.getTaskStack();
4136b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4146b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Return early if there are no tasks in the focused stack
4154b057c6787624b75613769a857ccdf51114bb7f2Winson        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
4166b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4176b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Return early if there is no running task
418d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
4196b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (runningTask == null) return;
4206b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4216b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Find the task in the recents list
422d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson        boolean isRunningTaskInHomeStack = SystemServicesProxy.isHomeStack(runningTask.stackId);
423250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = focusedStack.getStackTasks();
4246b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        Task toTask = null;
4256b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        ActivityOptions launchOpts = null;
4266b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        int taskCount = tasks.size();
4276b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        for (int i = taskCount - 1; i >= 1; i--) {
4286b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            Task task = tasks.get(i);
429d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            if (isRunningTaskInHomeStack) {
430e86deb8adb022ba7721a1af1112d3a45e757095cWinson                toTask = tasks.get(i - 1);
431e86deb8adb022ba7721a1af1112d3a45e757095cWinson                launchOpts = ActivityOptions.makeCustomAnimation(mContext,
432e86deb8adb022ba7721a1af1112d3a45e757095cWinson                        R.anim.recents_launch_next_affiliated_task_target,
433e86deb8adb022ba7721a1af1112d3a45e757095cWinson                        R.anim.recents_fast_toggle_app_home_exit);
434e86deb8adb022ba7721a1af1112d3a45e757095cWinson                break;
435e86deb8adb022ba7721a1af1112d3a45e757095cWinson            } else if (task.key.id == runningTask.id) {
4366b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                toTask = tasks.get(i - 1);
4376b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                launchOpts = ActivityOptions.makeCustomAnimation(mContext,
4386b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                        R.anim.recents_launch_prev_affiliated_task_target,
4396b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                        R.anim.recents_launch_prev_affiliated_task_source);
4406b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                break;
4416b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            }
4426b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
4436b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4446b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Return early if there is no next task
4456b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        if (toTask == null) {
4466b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            ssp.startInPlaceAnimationOnFrontMostApplication(
4476b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                    ActivityOptions.makeCustomInPlaceAnimation(mContext,
4486b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson                            R.anim.recents_launch_prev_affiliated_task_bounce));
4496b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson            return;
4506b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        }
4516b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4526b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson        // Launch the task
45364ae08aa16fdf7ee33073979400afa40692342f1Wale Ogunwale        ssp.startActivityFromRecents(mContext, toTask.key, toTask.title, launchOpts);
4546b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    }
4556b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson
4566b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson    /**
4576b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     * Transitions to the next affiliated task.
4586b92c6e524dbb7598fbeb4aefd98b69e6c13c03aWinson     */
459190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showRelativeAffiliatedTask(boolean showNextTask) {
460e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
461e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
462190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
463dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson        loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
464190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStack focusedStack = plan.getTaskStack();
465190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
466190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there are no tasks in the focused stack
4674b057c6787624b75613769a857ccdf51114bb7f2Winson        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
468190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
469190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no running task (can't determine affiliated tasks in this case)
470d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
471190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (runningTask == null) return;
472190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if the running task is in the home stack (optimization)
4735510f6c1b9c20483e1507147eed7b24ac8bb6363Winson        if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return;
474190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
475190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Find the task in the recents list
476250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = focusedStack.getStackTasks();
477190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Task toTask = null;
478190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ActivityOptions launchOpts = null;
479190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        int taskCount = tasks.size();
480190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        int numAffiliatedTasks = 0;
481190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        for (int i = 0; i < taskCount; i++) {
482190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Task task = tasks.get(i);
483190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (task.key.id == runningTask.id) {
484190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                TaskGrouping group = task.group;
485190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                Task.TaskKey toTaskKey;
486190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (showNextTask) {
487190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTaskKey = group.getNextTaskInGroup(task);
488190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
489190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_next_affiliated_task_target,
490190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_next_affiliated_task_source);
491190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
492190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTaskKey = group.getPrevTaskInGroup(task);
493190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
494190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_prev_affiliated_task_target,
495190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_prev_affiliated_task_source);
496190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
497190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (toTaskKey != null) {
498190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTask = focusedStack.findTaskWithId(toTaskKey.id);
499190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
500190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                numAffiliatedTasks = group.getTaskCount();
501190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                break;
502190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
503190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
504190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
505190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no next task
506190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTask == null) {
507190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (numAffiliatedTasks > 1) {
508190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (showNextTask) {
509e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    ssp.startInPlaceAnimationOnFrontMostApplication(
510190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
511190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                                    R.anim.recents_launch_next_affiliated_task_bounce));
512190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
513e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    ssp.startInPlaceAnimationOnFrontMostApplication(
514190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
515190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                                    R.anim.recents_launch_prev_affiliated_task_bounce));
516190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
517190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
518190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return;
519190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
520190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
521190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of actually launched affiliated tasks
522190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
523190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
524190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Launch the task
52564ae08aa16fdf7ee33073979400afa40692342f1Wale Ogunwale        ssp.startActivityFromRecents(mContext, toTask.key, toTask.title, launchOpts);
526190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
527190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
528190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showNextAffiliatedTask() {
529190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of when the affiliated task is triggered
530190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_next", 1);
531190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        showRelativeAffiliatedTask(true);
532190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
533190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
534190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showPrevAffiliatedTask() {
535190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of when the affiliated task is triggered
536190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1);
537190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        showRelativeAffiliatedTask(false);
538190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
539190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
540cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi    public void dockTopTask(int topTaskId, int dragMode,
541cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi            int stackCreateMode, Rect initialBounds) {
54275b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi        SystemServicesProxy ssp = Recents.getSystemServices();
5439511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi
5449511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi        // Make sure we inform DividerView before we actually start the activity so we can change
5459511b0f1e9ac629a4a747a0c9373d33ab33cfc32Jorim Jaggi        // the resize mode already.
546e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang        if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {
547899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi            EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
548e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang            showRecents(
549e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang                    false /* triggeredFromAltTab */,
550e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang                    dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
551e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang                    false /* animate */,
552681fc7b2670542aae0f3b9ef8f6c7a88db984ea9Jorim Jaggi                    true /* launchedWhileDockingTask*/,
553db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                    false /* fromHome */,
554db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                    DividerView.INVALID_RECENTS_GROW_TARGET);
555e4fbd328f83ea0ee086731f852cd6c56a3deb733Chong Zhang        }
55675b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi    }
55775b2597e5826662c1740d6f3b81966a9e6a9e7b4Jorim Jaggi
558190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
559190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Returns the preloaded load plan and invalidates it.
560190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
561190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
562190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = sInstanceLoadPlan;
563190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        sInstanceLoadPlan = null;
564190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return plan;
565190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
566190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
567190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
568670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson     * Reloads all the resources for the current configuration.
569b94443d876d3c9575e88078d0e537bb385f79ca4Winson     */
570670ea71f1b4ae59a0cd6608ae44b0fb78a1144c4Winson    private void reloadResources() {
571b94443d876d3c9575e88078d0e537bb385f79ca4Winson        Resources res = mContext.getResources();
572b94443d876d3c9575e88078d0e537bb385f79ca4Winson
573b94443d876d3c9575e88078d0e537bb385f79ca4Winson        mStatusBarHeight = res.getDimensionPixelSize(
574b94443d876d3c9575e88078d0e537bb385f79ca4Winson                com.android.internal.R.dimen.status_bar_height);
575b94443d876d3c9575e88078d0e537bb385f79ca4Winson        mNavBarHeight = res.getDimensionPixelSize(
576b94443d876d3c9575e88078d0e537bb385f79ca4Winson                com.android.internal.R.dimen.navigation_bar_height);
577b94443d876d3c9575e88078d0e537bb385f79ca4Winson        mNavBarWidth = res.getDimensionPixelSize(
578b94443d876d3c9575e88078d0e537bb385f79ca4Winson                com.android.internal.R.dimen.navigation_bar_width);
57925160db73f37619a26a3d87a06625925d881b0fdJorim Jaggi        mTaskBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(mContext,
580217009356efa2b854ab3981dff8d315a0d679c73Winson                R.dimen.recents_task_view_header_height,
581217009356efa2b854ab3981dff8d315a0d679c73Winson                R.dimen.recents_task_view_header_height,
582217009356efa2b854ab3981dff8d315a0d679c73Winson                R.dimen.recents_task_view_header_height,
583217009356efa2b854ab3981dff8d315a0d679c73Winson                R.dimen.recents_task_view_header_height_tablet_land,
584217009356efa2b854ab3981dff8d315a0d679c73Winson                R.dimen.recents_task_view_header_height,
585217009356efa2b854ab3981dff8d315a0d679c73Winson                R.dimen.recents_task_view_header_height_tablet_land);
586b94443d876d3c9575e88078d0e537bb385f79ca4Winson    }
587b94443d876d3c9575e88078d0e537bb385f79ca4Winson
588b94443d876d3c9575e88078d0e537bb385f79ca4Winson    /**
589190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Prepares the header bar layout for the next transition, if the task view bounds has changed
590190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * since the last call, it will attempt to re-measure and layout the header bar to the new size.
591190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     *
592f0d1c44a59a10707baa0cca8dd377302260710c1Winson     * @param stack the stack to initialize the stack layout with
593db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi     * @param windowRectOverride the rectangle to use when calculating the stack state which can
594db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi     *                           be different from the current window rect if recents is resizing
595db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi     *                           while being launched
596190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
597db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi    private void updateHeaderBarLayout(TaskStack stack, Rect windowRectOverride) {
598e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
599fc48b072e8caa62849ee305f89f38d248d4a1dedWinson        Rect displayRect = ssp.getDisplayRect();
600c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        Rect systemInsets = new Rect();
601c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        ssp.getStableInsets(systemInsets);
602db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        Rect windowRect = windowRectOverride != null
603db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                ? new Rect(windowRectOverride)
604db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                : ssp.getWindowRect();
605cf9b8326cecfca3917779c3701aa08eaaad56505Winson        // When docked, the nav bar insets are consumed and the activity is measured without insets.
606cf9b8326cecfca3917779c3701aa08eaaad56505Winson        // However, the window bounds include the insets, so we need to subtract them here to make
607cf9b8326cecfca3917779c3701aa08eaaad56505Winson        // them identical.
608cf9b8326cecfca3917779c3701aa08eaaad56505Winson        if (ssp.hasDockedTask()) {
609cf9b8326cecfca3917779c3701aa08eaaad56505Winson            windowRect.bottom -= systemInsets.bottom;
610cf9b8326cecfca3917779c3701aa08eaaad56505Winson            systemInsets.bottom = 0;
611cf9b8326cecfca3917779c3701aa08eaaad56505Winson        }
612c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        calculateWindowStableInsets(systemInsets, windowRect);
613c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        windowRect.offsetTo(0, 0);
614190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
61559924fe0d9136cf349759bea1e06b661603f95feWinson        TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
616190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
617190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Rebind the header bar and draw it for the transition
6188873754f66527d2cc9feab295dd4eef23298212aWinson        stackLayout.setSystemInsets(systemInsets);
619f0d1c44a59a10707baa0cca8dd377302260710c1Winson        if (stack != null) {
620fc48b072e8caa62849ee305f89f38d248d4a1dedWinson            stackLayout.getTaskStackBounds(displayRect, windowRect, systemInsets.top,
621cbb625bc6d22ad806560dd192d3945cdd5021cfbWinson                    systemInsets.left, systemInsets.right, mTaskStackBounds);
622aeb298c4db913b376fb6053ec30c132a93e04635Winson            stackLayout.reset();
623fc48b072e8caa62849ee305f89f38d248d4a1dedWinson            stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
624f0d1c44a59a10707baa0cca8dd377302260710c1Winson                    TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
625a1ededd056d51532ab18354f17f8065ec1134535Winson            mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
626190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
627aeb298c4db913b376fb6053ec30c132a93e04635Winson            Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
62894bc4f2238d8eefb77c63a560aa0de1335ee57abWinson            if (!taskViewBounds.isEmpty()) {
62994bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                int taskViewWidth = taskViewBounds.width();
63094bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                synchronized (mHeaderBarLock) {
63194bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                    if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
63294bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                            mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
63396f78f50464a0f394802ff0709ba7276976ef275Winson                        mHeaderBar.forceLayout();
63494bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                        mHeaderBar.measure(
63594bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                                MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
63694bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                                MeasureSpec.makeMeasureSpec(mTaskBarHeight, MeasureSpec.EXACTLY));
63794bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                    }
63894bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                    mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
639aeb298c4db913b376fb6053ec30c132a93e04635Winson                }
640aeb298c4db913b376fb6053ec30c132a93e04635Winson
64194bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                // Update the transition bitmap to match the new header bar height
64294bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                if (mThumbTransitionBitmapCache == null ||
64394bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                        (mThumbTransitionBitmapCache.getWidth() != taskViewWidth) ||
64494bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                        (mThumbTransitionBitmapCache.getHeight() != mTaskBarHeight)) {
64594bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                    mThumbTransitionBitmapCache = Bitmap.createBitmap(taskViewWidth,
64694bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                            mTaskBarHeight, Bitmap.Config.ARGB_8888);
64794bc4f2238d8eefb77c63a560aa0de1335ee57abWinson                }
648aeb298c4db913b376fb6053ec30c132a93e04635Winson            }
649190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
650190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
651190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
652190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
653c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi     * Given the stable insets and the rect for our window, calculates the insets that affect our
654c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi     * window.
655c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi     */
656c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi    private void calculateWindowStableInsets(Rect inOutInsets, Rect windowRect) {
657c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        Rect displayRect = Recents.getSystemServices().getDisplayRect();
658c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi
659c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        // Display rect without insets - available app space
660c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        Rect appRect = new Rect(displayRect);
661c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        appRect.inset(inOutInsets);
662c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi
663c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        // Our window intersected with available app space
664c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        Rect windowRectWithInsets = new Rect(windowRect);
665c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        windowRectWithInsets.intersect(appRect);
666c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        inOutInsets.left = windowRectWithInsets.left - windowRect.left;
667c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        inOutInsets.top = windowRectWithInsets.top - windowRect.top;
668c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        inOutInsets.right = windowRect.right - windowRectWithInsets.right;
669c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi        inOutInsets.bottom = windowRect.bottom - windowRectWithInsets.bottom;
670c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi    }
671c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi
672c6c89a82144f59475242c75d67529fed943ae30bJorim Jaggi    /**
673190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Preloads the icon of a task.
674190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
675c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson    private void preloadIcon(int runningTaskId) {
676190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Ensure that we load the running task's icon
677190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
678c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson        launchOpts.runningTaskId = runningTaskId;
679190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.loadThumbnails = false;
680190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.onlyLoadForCache = true;
681e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
682190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
683190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
684190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
685190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for a unknown state->recents transition.
686190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
6874bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan    protected ActivityOptions getUnknownTransitionActivityOptions() {
688190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return ActivityOptions.makeCustomAnimation(mContext,
689190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_unknown_enter,
690190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_unknown_exit,
6913fb67562c548662910160d5672b1b9558bd6571cWinson                mHandler, null);
692190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
693190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
694190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
695190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for a home->recents transition.
696190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
697008ee15fe82c8216e8e4f67e3032de468cc6c92aWinson    protected ActivityOptions getHomeTransitionActivityOptions() {
698190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return ActivityOptions.makeCustomAnimation(mContext,
699190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_launcher_enter,
700190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_launcher_exit,
7013fb67562c548662910160d5672b1b9558bd6571cWinson                mHandler, null);
702190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
703190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
704190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
705190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for an app->recents transition.
706190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
707190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getThumbnailTransitionActivityOptions(
708d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            ActivityManager.RunningTaskInfo runningTask, TaskStackView stackView,
709d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson                    Rect windowOverrideRect) {
710c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson        if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
711d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
712e693aafe0511c2a7ffc571b22abeefba44046225Winson            ArrayList<Task> tasks = stackView.getStack().getStackTasks();
713e693aafe0511c2a7ffc571b22abeefba44046225Winson            TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
714e693aafe0511c2a7ffc571b22abeefba44046225Winson            TaskStackViewScroller stackScroller = stackView.getScroller();
715e693aafe0511c2a7ffc571b22abeefba44046225Winson
716003eda6c230a1b1c4e3709466c46660e7602d740Winson            stackView.updateLayoutAlgorithm(true /* boundScroll */);
71767c79578f94646bade5d336af0d4491179c1b37dWinson            stackView.updateToInitialState();
718e693aafe0511c2a7ffc571b22abeefba44046225Winson
719d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            for (int i = tasks.size() - 1; i >= 0; i--) {
720d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                Task task = tasks.get(i);
721387aac6ad7bde21f2c2510cb8a2f3af3959721e0Winson                if (task.isFreeformTask()) {
722e693aafe0511c2a7ffc571b22abeefba44046225Winson                    mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task,
723db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                            stackScroller.getStackScroll(), mTmpTransform, null,
724db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                            windowOverrideRect);
725aeb298c4db913b376fb6053ec30c132a93e04635Winson                    Bitmap thumbnail = drawThumbnailTransitionBitmap(task, mTmpTransform,
726aeb298c4db913b376fb6053ec30c132a93e04635Winson                            mThumbTransitionBitmapCache);
727d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    Rect toTaskRect = new Rect();
728d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    mTmpTransform.rect.round(toTaskRect);
729d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                    specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
730d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                }
731d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            }
732d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
733d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            specs.toArray(specsArray);
734d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
7353fb67562c548662910160d5672b1b9558bd6571cWinson                    specsArray, mHandler, null, this);
736d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski        } else {
737d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            // Update the destination rect
738d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            Task toTask = new Task();
739db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi            TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask,
740db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                    windowOverrideRect);
741aeb298c4db913b376fb6053ec30c132a93e04635Winson            Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
742aeb298c4db913b376fb6053ec30c132a93e04635Winson                    mThumbTransitionBitmapCache);
743d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            if (thumbnail != null) {
744aeb298c4db913b376fb6053ec30c132a93e04635Winson                RectF toTaskRect = toTransform.rect;
745d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
746d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski                        thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
7473fb67562c548662910160d5672b1b9558bd6571cWinson                        (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null);
748d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            }
749d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            // If both the screenshot and thumbnail fails, then just fall back to the default transition
750d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski            return getUnknownTransitionActivityOptions();
751d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski        }
752d64ef3ef33c50a03b4be3b2baaa93aab7319fca8Filip Gruszczynski    }
753190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
754190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
755190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Returns the transition rect for the given task id.
756190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
757e693aafe0511c2a7ffc571b22abeefba44046225Winson    private TaskViewTransform getThumbnailTransitionTransform(TaskStackView stackView,
758db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi            Task runningTaskOut, Rect windowOverrideRect) {
759190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Find the running task in the TaskStack
760e693aafe0511c2a7ffc571b22abeefba44046225Winson        TaskStack stack = stackView.getStack();
76165c851e6e9e08656744b6f66d3da188e3283b17dWinson        Task launchTask = stack.getLaunchTarget();
76265c851e6e9e08656744b6f66d3da188e3283b17dWinson        if (launchTask != null) {
76365c851e6e9e08656744b6f66d3da188e3283b17dWinson            runningTaskOut.copyFrom(launchTask);
76465c851e6e9e08656744b6f66d3da188e3283b17dWinson        } else {
765190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If no task is specified or we can not find the task just use the front most one
76635a8b04140598a5b5c4865254b942adb6a830991Winson            launchTask = stack.getStackFrontMostTask(true /* includeFreeform */);
76765c851e6e9e08656744b6f66d3da188e3283b17dWinson            runningTaskOut.copyFrom(launchTask);
768190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
769190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
770190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Get the transform for the running task
771003eda6c230a1b1c4e3709466c46660e7602d740Winson        stackView.updateLayoutAlgorithm(true /* boundScroll */);
77267c79578f94646bade5d336af0d4491179c1b37dWinson        stackView.updateToInitialState();
7737845e8c4946f6b5dadfcd9c1d64e826bacc50edbWinson        stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
774db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                stackView.getScroller().getStackScroll(), mTmpTransform, null, windowOverrideRect);
775190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return mTmpTransform;
776190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
777190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
778190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
779190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Draws the header of a task used for the window animation into a bitmap.
780190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
781aeb298c4db913b376fb6053ec30c132a93e04635Winson    private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform,
782aeb298c4db913b376fb6053ec30c132a93e04635Winson            Bitmap thumbnail) {
7838be1634a543022bd6ee0c1e974d3201d452981e8Winson        SystemServicesProxy ssp = Recents.getSystemServices();
784190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTransform != null && toTask.key != null) {
785190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            synchronized (mHeaderBarLock) {
7868be1634a543022bd6ee0c1e974d3201d452981e8Winson                boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
787509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung                mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
788509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung                        (int) toTransform.rect.height());
789c742f973b1e506732911c156c5869fd377afc5bfWinson                if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
790190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    thumbnail.eraseColor(0xFFff0000);
791190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
792aeb298c4db913b376fb6053ec30c132a93e04635Winson                    thumbnail.eraseColor(0);
793190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    Canvas c = new Canvas(thumbnail);
79422574afa00b7e32b7c4c5a1b98deebd67751b364Winson                    // Workaround for b/27815919, reset the callback so that we do not trigger an
79522574afa00b7e32b7c4c5a1b98deebd67751b364Winson                    // invalidate on the header bar as a result of updating the icon
79622574afa00b7e32b7c4c5a1b98deebd67751b364Winson                    Drawable icon = mHeaderBar.getIconView().getDrawable();
79722574afa00b7e32b7c4c5a1b98deebd67751b364Winson                    if (icon != null) {
79822574afa00b7e32b7c4c5a1b98deebd67751b364Winson                        icon.setCallback(null);
79922574afa00b7e32b7c4c5a1b98deebd67751b364Winson                    }
800d2a030613154e2007d9816e090c39e9726e7adbaWinson                    mHeaderBar.bindToTask(toTask, false /* touchExplorationEnabled */,
8018be1634a543022bd6ee0c1e974d3201d452981e8Winson                            disabledInSafeMode);
802d2a030613154e2007d9816e090c39e9726e7adbaWinson                    mHeaderBar.onTaskDataLoaded();
803e693aafe0511c2a7ffc571b22abeefba44046225Winson                    mHeaderBar.setDimAlpha(toTransform.dimAlpha);
804190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mHeaderBar.draw(c);
805190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    c.setBitmap(null);
806190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
807190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
808190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return thumbnail.createAshmemBitmap();
809190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
810190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return null;
811190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
812190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
813190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
814190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Shows the recents activity
815190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
816d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
817d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            boolean isHomeStackVisible, boolean animate, int growTarget) {
818e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
819c5b12dd37e964b220c0a108e86ad8a2d12805747Winson        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
820fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        SystemServicesProxy ssp = Recents.getSystemServices();
821fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        boolean isBlacklisted = (runningTask != null)
822fc73eec235131dbf3216891f3cb2b1407e6cc099Winson                ? ssp.isBlackListedActivity(runningTask.baseActivity.getClassName())
823fc73eec235131dbf3216891f3cb2b1407e6cc099Winson                : false;
824190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
825fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        int runningTaskId = !mLaunchedWhileDocking && !isBlacklisted && (runningTask != null)
826c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson                ? runningTask.id
827c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson                : -1;
828c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson
829e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson        // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
830435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi        // should always preload the tasks now. If we are dragging in recents, reload them as
831435b2e43cb131d0b38ba19f335aec78bb83944b2Jorim Jaggi        // the stacks might have changed.
832fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        if (mLaunchedWhileDocking || mTriggeredFromAltTab || sInstanceLoadPlan == null) {
833e5f1faa9f8009a723ab21aed6fe5ab325c61442bWinson            // Create a new load plan if preloadRecents() was never triggered
834190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            sInstanceLoadPlan = loader.createLoadPlan(mContext);
835190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
836e161f08e98fdbe6fe83f70ffa1ea11142a027ebeJorim Jaggi        if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
837c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson            loader.preloadTasks(sInstanceLoadPlan, runningTaskId, !isHomeStackVisible);
838190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
839c5b12dd37e964b220c0a108e86ad8a2d12805747Winson
840190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStack stack = sInstanceLoadPlan.getTaskStack();
841c5b12dd37e964b220c0a108e86ad8a2d12805747Winson        boolean hasRecentTasks = stack.getTaskCount() > 0;
842fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        boolean useThumbnailTransition = (runningTask != null) && !isHomeStackVisible &&
843fc73eec235131dbf3216891f3cb2b1407e6cc099Winson                hasRecentTasks;
844190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
845aeb298c4db913b376fb6053ec30c132a93e04635Winson        // Update the launch state that we need in updateHeaderBarLayout()
846c5887ea7a0b82cc5909743ce14cbda1dcf1dfc82Jorim Jaggi        launchState.launchedFromHome = !useThumbnailTransition && !mLaunchedWhileDocking;
847aeb298c4db913b376fb6053ec30c132a93e04635Winson        launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking;
848fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        launchState.launchedFromBlacklistedApp = launchState.launchedFromApp && isBlacklisted;
849aeb298c4db913b376fb6053ec30c132a93e04635Winson        launchState.launchedViaDockGesture = mLaunchedWhileDocking;
850aeb298c4db913b376fb6053ec30c132a93e04635Winson        launchState.launchedViaDragGesture = mDraggingInRecents;
851c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson        launchState.launchedToTaskId = runningTaskId;
852aeb298c4db913b376fb6053ec30c132a93e04635Winson        launchState.launchedWithAltTab = mTriggeredFromAltTab;
853aeb298c4db913b376fb6053ec30c132a93e04635Winson
854aeb298c4db913b376fb6053ec30c132a93e04635Winson        // Preload the icon (this will be a null-op if we have preloaded the icon already in
855aeb298c4db913b376fb6053ec30c132a93e04635Winson        // preloadRecents())
856c4a038ad28009eb5840cf9f6aefbd2c873cee02eWinson        preloadIcon(runningTaskId);
857aeb298c4db913b376fb6053ec30c132a93e04635Winson
858f0d1c44a59a10707baa0cca8dd377302260710c1Winson        // Update the header bar if necessary
859db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        Rect windowOverrideRect = getWindowRectOverride(growTarget);
860db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        updateHeaderBarLayout(stack, windowOverrideRect);
861f0d1c44a59a10707baa0cca8dd377302260710c1Winson
862190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Prepare the dummy stack for the transition
86336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        TaskStackLayoutAlgorithm.VisibilityReport stackVr =
864190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mDummyStackView.computeStackVisibilityReport();
865bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi
866aeb298c4db913b376fb6053ec30c132a93e04635Winson        // Update the remaining launch state
867c5b12dd37e964b220c0a108e86ad8a2d12805747Winson        launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
868c5b12dd37e964b220c0a108e86ad8a2d12805747Winson        launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails;
869c5b12dd37e964b220c0a108e86ad8a2d12805747Winson
870bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi        if (!animate) {
871c5b12dd37e964b220c0a108e86ad8a2d12805747Winson            startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
872bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi            return;
873bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi        }
874bb42a46631b4cecdd03bd628feeb8270d412ebd3Jorim Jaggi
875aeb298c4db913b376fb6053ec30c132a93e04635Winson        ActivityOptions opts;
876fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        if (isBlacklisted) {
877fc73eec235131dbf3216891f3cb2b1407e6cc099Winson            opts = getUnknownTransitionActivityOptions();
878fc73eec235131dbf3216891f3cb2b1407e6cc099Winson        } else if (useThumbnailTransition) {
879190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Try starting with a thumbnail transition
880d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson            opts = getThumbnailTransitionActivityOptions(runningTask, mDummyStackView,
881db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                    windowOverrideRect);
882aeb298c4db913b376fb6053ec30c132a93e04635Winson        } else {
883fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan            // If there is no thumbnail transition, but is launching from home into recents, then
884008ee15fe82c8216e8e4f67e3032de468cc6c92aWinson            // use a quick home transition
885aeb298c4db913b376fb6053ec30c132a93e04635Winson            opts = hasRecentTasks
886aeb298c4db913b376fb6053ec30c132a93e04635Winson                ? getHomeTransitionActivityOptions()
887aeb298c4db913b376fb6053ec30c132a93e04635Winson                : getUnknownTransitionActivityOptions();
888fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan        }
889aeb298c4db913b376fb6053ec30c132a93e04635Winson        startRecentsActivity(opts);
890fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan        mLastToggleTime = SystemClock.elapsedRealtime();
891fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan    }
892fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan
893db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi    private Rect getWindowRectOverride(int growTarget) {
894db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        if (growTarget == DividerView.INVALID_RECENTS_GROW_TARGET) {
895db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi            return null;
896db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        }
897db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        Rect result = new Rect();
898db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        Rect displayRect = Recents.getSystemServices().getDisplayRect();
899db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        DockedDividerUtils.calculateBoundsForPosition(growTarget, WindowManager.DOCKED_BOTTOM,
900db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                result, displayRect.width(), displayRect.height(),
901db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi                Recents.getSystemServices().getDockedDividerSize(mContext));
902db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi        return result;
903db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi    }
904db21bbd2caf05322864f09ec45a0c572cf071123Jorim Jaggi
905fa61ce343e91e11bb06545eae00e0659a2942a7dSid Soundararajan    /**
906190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Starts the recents activity.
907190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
908c5b12dd37e964b220c0a108e86ad8a2d12805747Winson    private void startRecentsActivity(ActivityOptions opts) {
909190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Intent intent = new Intent();
9104bdb6879bd5f1b7e93e7e9ac236a073921862075Sid Soundararajan        intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
911190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
912190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
913190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
914b58c46acec2e270f24ca587a64298f06cefb09cbSid Soundararajan
915190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (opts != null) {
916190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
917190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } else {
918190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
919190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
920cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi        EventBus.getDefault().send(new RecentsActivityStartingEvent());
921190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
922190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
9233fb67562c548662910160d5672b1b9558bd6571cWinson    /**** OnAnimationFinishedListener Implementation ****/
9241a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski
9251a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski    @Override
9261a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski    public void onAnimationFinished() {
9271a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski        EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent());
9281a5203dfd5264104db018b8a09d50075b1af9b2dFilip Gruszczynski    }
929190fe3bf88388fcb109af64571e3baa0d01f1c37Winson}
930