RecentsImpl.java revision 3150e574e6e903a17193e0b90433d69c0e20ae4c
1190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/*
2190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Copyright (C) 2015 The Android Open Source Project
3190fe3bf88388fcb109af64571e3baa0d01f1c37Winson *
4190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Licensed under the Apache License, Version 2.0 (the "License");
5190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * you may not use this file except in compliance with the License.
6190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * You may obtain a copy of the License at
7190fe3bf88388fcb109af64571e3baa0d01f1c37Winson *
8190fe3bf88388fcb109af64571e3baa0d01f1c37Winson *      http://www.apache.org/licenses/LICENSE-2.0
9190fe3bf88388fcb109af64571e3baa0d01f1c37Winson *
10190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * Unless required by applicable law or agreed to in writing, software
11190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * distributed under the License is distributed on an "AS IS" BASIS,
12190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * See the License for the specific language governing permissions and
14190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * limitations under the License.
15190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */
16190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
17190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonpackage com.android.systemui.recents;
18190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
19190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityManager;
20190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ActivityOptions;
21190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.app.ITaskStackListener;
22190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.ActivityNotFoundException;
23190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Context;
24190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.Intent;
25190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.content.res.Resources;
26190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Bitmap;
27190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Canvas;
28190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.graphics.Rect;
293150e574e6e903a17193e0b90433d69c0e20ae4cWinsonimport android.graphics.RectF;
30190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.Handler;
31190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.SystemClock;
32190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.os.UserHandle;
33190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.util.MutableBoolean;
34190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.LayoutInflater;
35190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport android.view.View;
36190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.internal.logging.MetricsLogger;
37190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.Prefs;
38190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.R;
39190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.SystemUIApplication;
40412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.EventBus;
41412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
42412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.HideRecentsEvent;
43412e18058dc2cd5779d2451fce7fd74631f9e237Winsonimport com.android.systemui.recents.events.activity.ToggleRecentsEvent;
44190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
45190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
46190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.misc.Console;
47ab84fc56114c0963c6f701de9725f5413ab76da9Winsonimport com.android.systemui.recents.misc.ForegroundThread;
48190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.misc.SystemServicesProxy;
49190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoadPlan;
50190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.RecentsTaskLoader;
51190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.Task;
52190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskGrouping;
53190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.model.TaskStack;
54190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskStackView;
55190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
56190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewHeader;
57190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.recents.views.TaskViewTransform;
58190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport com.android.systemui.statusbar.phone.PhoneStatusBar;
59190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
60190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonimport java.util.ArrayList;
61190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
62190fe3bf88388fcb109af64571e3baa0d01f1c37Winson/**
63190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * An implementation of the Recents component for the current user.  For secondary users, this can
64190fe3bf88388fcb109af64571e3baa0d01f1c37Winson * be called remotely from the system user.
65190fe3bf88388fcb109af64571e3baa0d01f1c37Winson */
66190fe3bf88388fcb109af64571e3baa0d01f1c37Winsonpublic class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
67190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        implements ActivityOptions.OnAnimationStartedListener {
68190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
69190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private final static String TAG = "RecentsImpl";
70ab84fc56114c0963c6f701de9725f5413ab76da9Winson    private final static boolean DEBUG = false;
71190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
72412e18058dc2cd5779d2451fce7fd74631f9e237Winson    private final static int sMinToggleDelay = 350;
73190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
74190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public final static String RECENTS_PACKAGE = "com.android.systemui";
75190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
76190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
77190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
78190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
79190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
80190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * task stacks and update recents accordingly.
81190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
82190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
83190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Handler mHandler;
84190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
85190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public TaskStackListenerImpl(Handler handler) {
86190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mHandler = handler;
87190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
88190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
89190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        @Override
90190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public void onTaskStackChanged() {
91190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Debounce any task stack changes
92190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mHandler.removeCallbacks(this);
93190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mHandler.post(this);
94190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
95190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
96190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        /** Preloads the next task */
97190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        public void run() {
98190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // TODO: Temporarily skip this if multi stack is enabled
99190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            /*
100190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            RecentsConfiguration config = RecentsConfiguration.getInstance();
101190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
102e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                RecentsTaskLoader loader = Recents.getTaskLoader();
103e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                SystemServicesProxy ssp = Recents.getSystemServices();
104190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
105190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
106190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Load the next task only if we aren't svelte
107190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
108190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                loader.preloadTasks(plan, true);
109190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
110190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // This callback is made when a new activity is launched and the old one is paused
111190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // so ignore the current activity and try and preload the thumbnail for the
112190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // previous one.
113190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (runningTaskInfo != null) {
114190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts.runningTaskId = runningTaskInfo.id;
115190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
116190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.numVisibleTasks = 2;
117190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.numVisibleTaskThumbnails = 2;
118190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.onlyLoadForCache = true;
119190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                launchOpts.onlyLoadPausedActivities = true;
120190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                loader.loadTasks(mContext, plan, launchOpts);
121190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
122190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            */
123190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
124190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
125190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
126e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    private static RecentsTaskLoadPlan sInstanceLoadPlan;
127190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
128190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Context mContext;
129190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Handler mHandler;
130190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskStackListenerImpl mTaskStackListener;
131190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    RecentsAppWidgetHost mAppWidgetHost;
132190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mBootCompleted;
133190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mStartAnimationTriggered;
134190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mCanReuseTaskStackViews = true;
135190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
136190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Task launching
137190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    RecentsConfiguration mConfig;
138190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mSearchBarBounds = new Rect();
139190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mTaskStackBounds = new Rect();
140190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Rect mLastTaskViewBounds = new Rect();
141190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskViewTransform mTmpTransform = new TaskViewTransform();
142190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mStatusBarHeight;
143190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mNavBarHeight;
144190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mNavBarWidth;
145190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    int mTaskBarHeight;
146190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
147190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Header (for transition)
148190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskViewHeader mHeaderBar;
149190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    final Object mHeaderBarLock = new Object();
150190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    TaskStackView mDummyStackView;
151190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
152190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    // Variables to keep track of if we need to start recents after binding
153190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    boolean mTriggeredFromAltTab;
154190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    long mLastToggleTime;
155190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
156190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Bitmap mThumbnailTransitionBitmapCache;
157190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    Task mThumbnailTransitionBitmapCacheKey;
158190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
159190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
160190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public RecentsImpl(Context context) {
161190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mContext = context;
162190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mHandler = new Handler();
163190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
164190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Resources res = mContext.getResources();
165190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        LayoutInflater inflater = LayoutInflater.from(mContext);
166190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
167ab84fc56114c0963c6f701de9725f5413ab76da9Winson        // Initialize the static foreground thread
168ab84fc56114c0963c6f701de9725f5413ab76da9Winson        ForegroundThread.get();
169ab84fc56114c0963c6f701de9725f5413ab76da9Winson
170190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Register the task stack listener
171190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTaskStackListener = new TaskStackListenerImpl(mHandler);
172e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
173e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ssp.registerTaskStackListener(mTaskStackListener);
174190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
175190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Initialize the static configuration resources
176e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        mConfig = RecentsConfiguration.initialize(mContext, ssp);
177190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
178190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
179190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
180190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
181190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mDummyStackView = new TaskStackView(mContext, new TaskStack());
182190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
183190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                null, false);
184190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
185190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
186190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // When we start, preload the data associated with the previous recent tasks.
187190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // We can use a new plan since the caches will be the same.
188e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
189190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
190190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.preloadTasks(plan, true /* isTopTaskHome */);
191190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
192190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
193190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
194190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.onlyLoadForCache = true;
195190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.loadTasks(mContext, plan, launchOpts);
196190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
197190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
198190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onBootCompleted() {
199190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mBootCompleted = true;
200190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
201190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
202190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
203190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
204190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onConfigurationChanged() {
205190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Don't reuse task stack views if the configuration changes
206190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mCanReuseTaskStackViews = false;
207190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mConfig.updateOnConfigurationChange();
208190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
209190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
210190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
211190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * This is only called from the system user's Recents.  Secondary users will instead proxy their
212190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * visibility change events through to the system user via
213190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
214190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
215190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onVisibilityChanged(Context context, boolean visible) {
216190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        SystemUIApplication app = (SystemUIApplication) context;
217190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
218190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (statusBar != null) {
219190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            statusBar.updateRecentsVisibility(visible);
220190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
221190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
222190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
223190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
224190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * This is only called from the system user's Recents.  Secondary users will instead proxy their
225190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * visibility change events through to the system user via
226190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}.
227190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
228190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onStartScreenPinning(Context context) {
229190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        SystemUIApplication app = (SystemUIApplication) context;
230190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
231190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (statusBar != null) {
232190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            statusBar.showScreenPinningRequest(false);
233190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
234190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
235190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
236190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
237190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showRecents(boolean triggeredFromAltTab) {
238190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTriggeredFromAltTab = triggeredFromAltTab;
239190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
240190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        try {
241190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Check if the top task is in the home stack, and start the recents activity
242e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            SystemServicesProxy ssp = Recents.getSystemServices();
243e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
244190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            MutableBoolean isTopTaskHome = new MutableBoolean(true);
245e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
246190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, isTopTaskHome.value);
247190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
248190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } catch (ActivityNotFoundException e) {
249190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Console.logRawError("Failed to launch RecentAppsIntent", e);
250190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
251190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
252190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
253190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
254190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
255190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (mBootCompleted) {
256190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Defer to the activity to handle hiding recents, if it handles it, then it must still
257190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // be visible
258e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
259412e18058dc2cd5779d2451fce7fd74631f9e237Winson                    triggeredFromHomeKey));
260190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
261190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
262190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
263190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
264190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void toggleRecents() {
265190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTriggeredFromAltTab = false;
266190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
267190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        try {
268190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If the user has toggled it too quickly, then just eat up the event here (it's better
269190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // than showing a janky screenshot).
270190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // NOTE: Ideally, the screenshot mechanism would take the window transform into account
271190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
272190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                return;
273190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
274190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
275190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If Recents is the front most activity, then we should just communicate with it
276190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // directly to launch the first task or dismiss itself
277e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            SystemServicesProxy ssp = Recents.getSystemServices();
278e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
279190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            MutableBoolean isTopTaskHome = new MutableBoolean(true);
280e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
281190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Notify recents to toggle itself
282e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                EventBus.getDefault().post(new ToggleRecentsEvent());
283190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mLastToggleTime = SystemClock.elapsedRealtime();
284190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                return;
285190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
286190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Otherwise, start the recents activity
287190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, isTopTaskHome.value);
288190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
289190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } catch (ActivityNotFoundException e) {
290190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Console.logRawError("Failed to launch RecentAppsIntent", e);
291190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
292190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
293190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
294190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
295190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void preloadRecents() {
296190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Preload only the raw task list into a new load plan (which will be consumed by the
297190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // RecentsActivity) only if there is a task to animate to.
298e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
299e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
300190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MutableBoolean topTaskHome = new MutableBoolean(true);
301e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
302190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        sInstanceLoadPlan = loader.createLoadPlan(mContext);
303e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
304190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
305190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
306190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStack stack = sInstanceLoadPlan.getTaskStack();
307190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (stack.getTaskCount() > 0) {
308ab84fc56114c0963c6f701de9725f5413ab76da9Winson                // We try and draw the thumbnail transition bitmap in parallel before
309ab84fc56114c0963c6f701de9725f5413ab76da9Winson                // toggle/show recents is called
310190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView);
311190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
312190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
313190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
314190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
315190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
316190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void cancelPreloadingRecents() {
317190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Do nothing
318190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
319190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
320190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showRelativeAffiliatedTask(boolean showNextTask) {
321190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no focused stack
322e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
323e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        int focusedStackId = ssp.getFocusedStack();
324e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
325190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
326190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        loader.preloadTasks(plan, true /* isTopTaskHome */);
327190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStack focusedStack = plan.getTaskStack();
328190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
329190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there are no tasks in the focused stack
330190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
331190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
332e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
333190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no running task (can't determine affiliated tasks in this case)
334190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (runningTask == null) return;
335190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if the running task is in the home stack (optimization)
336e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        if (ssp.isInHomeStack(runningTask.id)) return;
337190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
338190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Find the task in the recents list
339190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ArrayList<Task> tasks = focusedStack.getTasks();
340190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Task toTask = null;
341190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ActivityOptions launchOpts = null;
342190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        int taskCount = tasks.size();
343190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        int numAffiliatedTasks = 0;
344190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        for (int i = 0; i < taskCount; i++) {
345190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Task task = tasks.get(i);
346190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (task.key.id == runningTask.id) {
347190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                TaskGrouping group = task.group;
348190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                Task.TaskKey toTaskKey;
349190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (showNextTask) {
350190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTaskKey = group.getNextTaskInGroup(task);
351190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
352190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_next_affiliated_task_target,
353190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_next_affiliated_task_source);
354190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
355190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTaskKey = group.getPrevTaskInGroup(task);
356190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
357190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_prev_affiliated_task_target,
358190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            R.anim.recents_launch_prev_affiliated_task_source);
359190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
360190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (toTaskKey != null) {
361190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    toTask = focusedStack.findTaskWithId(toTaskKey.id);
362190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
363190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                numAffiliatedTasks = group.getTaskCount();
364190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                break;
365190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
366190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
367190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
368190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Return early if there is no next task
369190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTask == null) {
370190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (numAffiliatedTasks > 1) {
371190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (showNextTask) {
372e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    ssp.startInPlaceAnimationOnFrontMostApplication(
373190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
374190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                                    R.anim.recents_launch_next_affiliated_task_bounce));
375190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
376e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    ssp.startInPlaceAnimationOnFrontMostApplication(
377190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
378190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                                    R.anim.recents_launch_prev_affiliated_task_bounce));
379190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
380190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
381190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return;
382190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
383190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
384190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of actually launched affiliated tasks
385190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
386190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
387190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Launch the task
388190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTask.isActive) {
389190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Bring an active task to the foreground
390e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ssp.moveTaskToFront(toTask.key.id, launchOpts);
391190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } else {
392e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
393190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
394190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
395190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
396190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showNextAffiliatedTask() {
397190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of when the affiliated task is triggered
398190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_next", 1);
399190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        showRelativeAffiliatedTask(true);
400190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
401190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
402190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void showPrevAffiliatedTask() {
403190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Keep track of when the affiliated task is triggered
404190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1);
405190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        showRelativeAffiliatedTask(false);
406190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
407190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
408190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
409190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Returns the preloaded load plan and invalidates it.
410190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
411190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
412190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan plan = sInstanceLoadPlan;
413190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        sInstanceLoadPlan = null;
414190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return plan;
415190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
416190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
417190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
418190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Prepares the header bar layout for the next transition, if the task view bounds has changed
419190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * since the last call, it will attempt to re-measure and layout the header bar to the new size.
420190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     *
421190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
422190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     *                               is not already bound (can be expensive)
423190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
424190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
425e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
426e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        Rect windowRect = ssp.getWindowRect();
427190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
428190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the configuration for the current state
429e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        mConfig.update(mContext, ssp, ssp.getWindowRect());
430190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
431190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (tryAndBindSearchWidget) {
432190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Try and pre-emptively bind the search widget on startup to ensure that we
433190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // have the right thumbnail bounds to animate to.
434190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Note: We have to reload the widget id before we get the task stack bounds below
435e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
436e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                mConfig.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds);
437190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
438190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
439190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Rect systemInsets = new Rect(0, mStatusBarHeight,
440190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
441190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                (mConfig.hasTransposedNavBar ? 0 : mNavBarHeight));
442190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mConfig.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
443190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mSearchBarBounds, mTaskStackBounds);
444190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
445190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Rebind the header bar and draw it for the transition
446190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
447190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Rect taskStackBounds = new Rect(mTaskStackBounds);
448190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        algo.setSystemInsets(systemInsets);
449190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
450190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
451190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (!taskViewBounds.equals(mLastTaskViewBounds)) {
452190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mLastTaskViewBounds.set(taskViewBounds);
453190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
454190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            int taskViewWidth = taskViewBounds.width();
455190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            synchronized (mHeaderBarLock) {
456190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mHeaderBar.measure(
457190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
458190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
459190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
460190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
461190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
462190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
463190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
464190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
465190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Preloads the icon of a task.
466190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
467190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void preloadIcon(ActivityManager.RunningTaskInfo task) {
468190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Ensure that we load the running task's icon
469190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
470190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.runningTaskId = task.id;
471190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.loadThumbnails = false;
472190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchOpts.onlyLoadForCache = true;
473e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
474190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
475190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
476190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
477190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Caches the header thumbnail used for a window animation asynchronously into
478190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * {@link #mThumbnailTransitionBitmapCache}.
479190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
480190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
481190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStack stack, TaskStackView stackView) {
482190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        preloadIcon(topTask);
483190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
484190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the header bar if necessary
485190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
486190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
487190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the destination rect
488190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mDummyStackView.updateMinMaxScrollForStack(stack);
489190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        final Task toTask = new Task();
490190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
491190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                topTask.id, toTask);
492ab84fc56114c0963c6f701de9725f5413ab76da9Winson        ForegroundThread.getHandler().post(new Runnable() {
493190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            @Override
494ab84fc56114c0963c6f701de9725f5413ab76da9Winson            public void run() {
495ab84fc56114c0963c6f701de9725f5413ab76da9Winson                final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform);
496ab84fc56114c0963c6f701de9725f5413ab76da9Winson                mHandler.post(new Runnable() {
497ab84fc56114c0963c6f701de9725f5413ab76da9Winson                    @Override
498ab84fc56114c0963c6f701de9725f5413ab76da9Winson                    public void run() {
499ab84fc56114c0963c6f701de9725f5413ab76da9Winson                        mThumbnailTransitionBitmapCache = transitionBitmap;
500ab84fc56114c0963c6f701de9725f5413ab76da9Winson                        mThumbnailTransitionBitmapCacheKey = toTask;
501ab84fc56114c0963c6f701de9725f5413ab76da9Winson                    }
502ab84fc56114c0963c6f701de9725f5413ab76da9Winson                });
503190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
504ab84fc56114c0963c6f701de9725f5413ab76da9Winson        });
505190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
506190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
507190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
508190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for a unknown state->recents transition.
509190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
510190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getUnknownTransitionActivityOptions() {
511190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return ActivityOptions.makeCustomAnimation(mContext,
512190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_unknown_enter,
513190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_unknown_exit,
514190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mHandler, this);
515190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
516190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
517190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
518190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for a home->recents transition.
519190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
520190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
521190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (fromSearchHome) {
522190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return ActivityOptions.makeCustomAnimation(mContext,
523190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    R.anim.recents_from_search_launcher_enter,
524190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    R.anim.recents_from_search_launcher_exit,
525190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mHandler, this);
526190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
527190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return ActivityOptions.makeCustomAnimation(mContext,
528190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_launcher_enter,
529190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                R.anim.recents_from_launcher_exit,
530190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mHandler, this);
531190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
532190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
533190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
534190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Creates the activity options for an app->recents transition.
535190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
536190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private ActivityOptions getThumbnailTransitionActivityOptions(
537190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
538190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
539190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the destination rect
540190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Task toTask = new Task();
541190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
542190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                topTask.id, toTask);
5433150e574e6e903a17193e0b90433d69c0e20ae4cWinson        RectF toTaskRect = toTransform.rect;
544190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Bitmap thumbnail;
545190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (mThumbnailTransitionBitmapCacheKey != null
546190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                && mThumbnailTransitionBitmapCacheKey.key != null
547190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
548190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            thumbnail = mThumbnailTransitionBitmapCache;
549190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mThumbnailTransitionBitmapCacheKey = null;
550190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mThumbnailTransitionBitmapCache = null;
551190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } else {
552190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            preloadIcon(topTask);
553190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
554190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
555190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (thumbnail != null) {
556190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
5573150e574e6e903a17193e0b90433d69c0e20ae4cWinson                    thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
5583150e574e6e903a17193e0b90433d69c0e20ae4cWinson                    (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
559190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
560190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
561190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // If both the screenshot and thumbnail fails, then just fall back to the default transition
562190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return getUnknownTransitionActivityOptions();
563190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
564190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
565190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
566190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Returns the transition rect for the given task id.
567190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
568190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
569190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            TaskStackView stackView, int runningTaskId, Task runningTaskOut) {
570190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Find the running task in the TaskStack
571190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Task task = null;
572190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        ArrayList<Task> tasks = stack.getTasks();
573190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (runningTaskId != -1) {
574190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Otherwise, try and find the task with the
575190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            int taskCount = tasks.size();
576190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            for (int i = taskCount - 1; i >= 0; i--) {
577190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                Task t = tasks.get(i);
578190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (t.key.id == runningTaskId) {
579190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    task = t;
580190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    runningTaskOut.copyFrom(t);
581190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    break;
582190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
583190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
584190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
585190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (task == null) {
586190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If no task is specified or we can not find the task just use the front most one
587190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            task = tasks.get(tasks.size() - 1);
588190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            runningTaskOut.copyFrom(task);
589190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
590190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
591190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Get the transform for the running task
592190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        stackView.getScroller().setStackScrollToInitialState();
593190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
594190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                stackView.getScroller().getStackScroll(), mTmpTransform, null);
595190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return mTmpTransform;
596190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
597190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
598190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
599190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Draws the header of a task used for the window animation into a bitmap.
600190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
601190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
602190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (toTransform != null && toTask.key != null) {
603190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            Bitmap thumbnail;
604190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            synchronized (mHeaderBarLock) {
605190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
606190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
607190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
608190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        Bitmap.Config.ARGB_8888);
609190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
610190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    thumbnail.eraseColor(0xFFff0000);
611190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                } else {
612190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    Canvas c = new Canvas(thumbnail);
613190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    c.scale(toTransform.scale, toTransform.scale);
614190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mHeaderBar.rebindToTask(toTask);
615190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mHeaderBar.draw(c);
616190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    c.setBitmap(null);
617190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                }
618190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
619190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            return thumbnail.createAshmemBitmap();
620190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
621190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        return null;
622190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
623190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
624190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
625190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Shows the recents activity
626190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
627190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
628190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            boolean isTopTaskHome) {
629e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
630e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        RecentsTaskLoader loader = Recents.getTaskLoader();
631190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
632190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the header bar if necessary
633190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
634190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
635190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (sInstanceLoadPlan == null) {
636190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Create a new load plan if onPreloadRecents() was never triggered
637190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            sInstanceLoadPlan = loader.createLoadPlan(mContext);
638190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
639190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
640190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (!sInstanceLoadPlan.hasTasks()) {
641190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
642190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
643190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStack stack = sInstanceLoadPlan.getTaskStack();
644190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
645190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Prepare the dummy stack for the transition
646190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mDummyStackView.updateMinMaxScrollForStack(stack);
647190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
648190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                mDummyStackView.computeStackVisibilityReport();
649190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        boolean hasRecentTasks = stack.getTaskCount() > 0;
650190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
651190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
652190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (useThumbnailTransition) {
653190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // Try starting with a thumbnail transition
654190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
655190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                    mDummyStackView);
656190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (opts != null) {
657190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, opts, false /* fromHome */,
658190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
659190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
660190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Fall through below to the non-thumbnail transition
661190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                useThumbnailTransition = false;
662190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
663190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
664190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
665190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (!useThumbnailTransition) {
666190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // If there is no thumbnail transition, but is launching from home into recents, then
667190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            // use a quick home transition and do the animation from home
668190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            if (hasRecentTasks) {
669e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String homeActivityPackage = ssp.getHomeActivityPackageName();
670e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String searchWidgetPackage = Prefs.getString(mContext,
671e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                        Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);
672190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
673190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Determine whether we are coming from a search owned home activity
674190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                boolean fromSearchHome = (homeActivityPackage != null) &&
675190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        homeActivityPackage.equals(searchWidgetPackage);
676190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
677190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
678190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        false /* fromThumbnail */, stackVr);
679190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            } else {
680190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                // Otherwise we do the normal fade from an unknown source
681190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                ActivityOptions opts = getUnknownTransitionActivityOptions();
682190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                startRecentsActivity(topTask, opts, true /* fromHome */,
683190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                        false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
684190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            }
685190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
686190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mLastToggleTime = SystemClock.elapsedRealtime();
687190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
688190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
689190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**
690190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     * Starts the recents activity.
691190fe3bf88388fcb109af64571e3baa0d01f1c37Winson     */
692190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
693190fe3bf88388fcb109af64571e3baa0d01f1c37Winson              ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
694190fe3bf88388fcb109af64571e3baa0d01f1c37Winson              TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
695e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        mStartAnimationTriggered = false;
696e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
697190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Update the configuration based on the launch options
698190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
699190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedFromHome = fromSearchHome || fromHome;
700190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedFromSearchHome = fromSearchHome;
701190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedFromAppWithThumbnail = fromThumbnail;
702190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
703190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedWithAltTab = mTriggeredFromAltTab;
704190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
705190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
706190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
707190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        launchState.launchedHasConfigurationChanged = false;
708190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
709190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        Intent intent = new Intent();
710190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
711190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
712190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
713190fe3bf88388fcb109af64571e3baa0d01f1c37Winson                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
714190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (opts != null) {
715190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
716190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        } else {
717190fe3bf88388fcb109af64571e3baa0d01f1c37Winson            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
718190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
719190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        mCanReuseTaskStackViews = true;
720190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
721190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
722190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    /**** OnAnimationStartedListener Implementation ****/
723190fe3bf88388fcb109af64571e3baa0d01f1c37Winson
724190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    @Override
725190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    public void onAnimationStarted() {
726190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        // Notify recents to start the enter animation
727190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        if (!mStartAnimationTriggered) {
728412e18058dc2cd5779d2451fce7fd74631f9e237Winson            mStartAnimationTriggered = true;
729e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            EventBus.getDefault().post(new EnterRecentsWindowAnimationStartedEvent());
730190fe3bf88388fcb109af64571e3baa0d01f1c37Winson        }
731190fe3bf88388fcb109af64571e3baa0d01f1c37Winson    }
732190fe3bf88388fcb109af64571e3baa0d01f1c37Winson}
733