RecentsActivity.java revision 606b3da71ab64e489e8f65e0b1092138dbfaf7b7
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.recents;
18
19import android.app.Activity;
20import android.app.ActivityOptions;
21import android.app.SearchManager;
22import android.appwidget.AppWidgetHostView;
23import android.appwidget.AppWidgetManager;
24import android.appwidget.AppWidgetProviderInfo;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.SharedPreferences;
30import android.os.Bundle;
31import android.os.UserHandle;
32import android.util.Pair;
33import android.view.KeyEvent;
34import android.view.View;
35import android.view.ViewStub;
36import android.widget.Toast;
37import com.android.systemui.R;
38import com.android.systemui.recents.misc.DebugTrigger;
39import com.android.systemui.recents.misc.ReferenceCountedTrigger;
40import com.android.systemui.recents.misc.SystemServicesProxy;
41import com.android.systemui.recents.misc.Utilities;
42import com.android.systemui.recents.model.RecentsTaskLoader;
43import com.android.systemui.recents.model.SpaceNode;
44import com.android.systemui.recents.model.Task;
45import com.android.systemui.recents.model.TaskStack;
46import com.android.systemui.recents.views.DebugOverlayView;
47import com.android.systemui.recents.views.RecentsView;
48import com.android.systemui.recents.views.SystemBarScrimViews;
49import com.android.systemui.recents.views.ViewAnimation;
50
51import java.lang.ref.WeakReference;
52import java.lang.reflect.InvocationTargetException;
53import java.util.ArrayList;
54
55/**
56 * The main Recents activity that is started from AlternateRecentsComponent.
57 */
58public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
59        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
60        DebugOverlayView.DebugOverlayViewCallbacks {
61
62    RecentsConfiguration mConfig;
63    boolean mVisible;
64    long mLastTabKeyEventTime;
65
66    // Top level views
67    RecentsView mRecentsView;
68    SystemBarScrimViews mScrimViews;
69    ViewStub mEmptyViewStub;
70    ViewStub mDebugOverlayStub;
71    View mEmptyView;
72    DebugOverlayView mDebugOverlay;
73
74    // Search AppWidget
75    RecentsAppWidgetHost mAppWidgetHost;
76    AppWidgetProviderInfo mSearchAppWidgetInfo;
77    AppWidgetHostView mSearchAppWidgetHostView;
78
79    // Runnables to finish the Recents activity
80    FinishRecentsRunnable mFinishLaunchHomeRunnable;
81
82    /**
83     * A common Runnable to finish Recents either by calling finish() (with a custom animation) or
84     * launching Home with some ActivityOptions.  Generally we always launch home when we exit
85     * Recents rather than just finishing the activity since we don't know what is behind Recents in
86     * the task stack.  The only case where we finish() directly is when we are cancelling the full
87     * screen transition from the app.
88     */
89    class FinishRecentsRunnable implements Runnable {
90        Intent mLaunchIntent;
91        ActivityOptions mLaunchOpts;
92
93        /**
94         * Creates a finish runnable that starts the specified intent, using the given
95         * ActivityOptions.
96         */
97        public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
98            mLaunchIntent = launchIntent;
99            mLaunchOpts = opts;
100        }
101
102        @Override
103        public void run() {
104            // Mark Recents as no longer visible
105            AlternateRecentsComponent.notifyVisibilityChanged(false);
106            mVisible = false;
107            // Finish Recents
108            if (mLaunchIntent != null) {
109                if (mLaunchOpts != null) {
110                    startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT);
111                } else {
112                    startActivityAsUser(mLaunchIntent, UserHandle.CURRENT);
113                }
114            } else {
115                finish();
116                overridePendingTransition(R.anim.recents_to_launcher_enter,
117                        R.anim.recents_to_launcher_exit);
118            }
119        }
120    }
121
122    /**
123     * Broadcast receiver to handle messages from AlternateRecentsComponent.
124     */
125    final BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
126        @Override
127        public void onReceive(Context context, Intent intent) {
128            String action = intent.getAction();
129            if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) {
130                // Mark Recents as no longer visible
131                AlternateRecentsComponent.notifyVisibilityChanged(false);
132                if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
133                    // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
134                    dismissRecentsToFocusedTaskOrHome(false);
135                } else if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
136                    // Otherwise, dismiss Recents to Home
137                    dismissRecentsToHome(true);
138                } else {
139                    // Do nothing, another activity is being launched on top of Recents
140                }
141            } else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
142                // If we are toggling Recents, then first unfilter any filtered stacks first
143                dismissRecentsToFocusedTaskOrHome(true);
144            } else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) {
145                // Try and start the enter animation (or restart it on configuration changed)
146                ReferenceCountedTrigger t = new ReferenceCountedTrigger(context, null, null, null);
147                mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
148                onEnterAnimationTriggered();
149                // Notify the fallback receiver that we have successfully got the broadcast
150                // See AlternateRecentsComponent.onAnimationStarted()
151                setResultCode(Activity.RESULT_OK);
152            }
153        }
154    };
155
156    /**
157     * Broadcast receiver to handle messages from the system
158     */
159    final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
160        @Override
161        public void onReceive(Context context, Intent intent) {
162            String action = intent.getAction();
163            if (action.equals(Intent.ACTION_SCREEN_OFF)) {
164                // When the screen turns off, dismiss Recents to Home
165                dismissRecentsToHome(false);
166            } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
167                // When the search activity changes, update the Search widget
168                refreshSearchWidget();
169            }
170        }
171    };
172
173    /**
174     * A custom debug trigger to listen for a debug key chord.
175     */
176    final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
177        @Override
178        public void run() {
179            onDebugModeTriggered();
180        }
181    });
182
183    /** Updates the set of recent tasks */
184    void updateRecentsTasks(Intent launchIntent) {
185        // Update the configuration based on the launch intent
186        boolean fromSearchHome = launchIntent.getBooleanExtra(
187                AlternateRecentsComponent.EXTRA_FROM_SEARCH_HOME, false);
188        mConfig.launchedFromHome = fromSearchHome || launchIntent.getBooleanExtra(
189                AlternateRecentsComponent.EXTRA_FROM_HOME, false);
190        mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
191                AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
192        mConfig.launchedToTaskId = launchIntent.getIntExtra(
193                AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1);
194        mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
195                AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
196
197        // Load all the tasks
198        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
199        SpaceNode root = loader.reload(this,
200                Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount,
201                mConfig.launchedFromHome);
202        ArrayList<TaskStack> stacks = root.getStacks();
203        if (!stacks.isEmpty()) {
204            mRecentsView.setTaskStacks(root.getStacks());
205        }
206        mConfig.launchedWithNoRecentTasks = !root.hasTasks();
207
208        // Create the home intent runnable
209        Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
210        homeIntent.addCategory(Intent.CATEGORY_HOME);
211        homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
212                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
213        mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
214            ActivityOptions.makeCustomAnimation(this,
215                fromSearchHome ? R.anim.recents_to_search_launcher_enter :
216                        R.anim.recents_to_launcher_enter,
217                fromSearchHome ? R.anim.recents_to_search_launcher_exit :
218                        R.anim.recents_to_launcher_exit));
219
220        // Mark the task that is the launch target
221        int taskStackCount = stacks.size();
222        if (mConfig.launchedToTaskId != -1) {
223            for (int i = 0; i < taskStackCount; i++) {
224                TaskStack stack = stacks.get(i);
225                ArrayList<Task> tasks = stack.getTasks();
226                int taskCount = tasks.size();
227                for (int j = 0; j < taskCount; j++) {
228                    Task t = tasks.get(j);
229                    if (t.key.id == mConfig.launchedToTaskId) {
230                        t.isLaunchTarget = true;
231                        break;
232                    }
233                }
234            }
235        }
236
237        // Update the top level view's visibilities
238        if (mConfig.launchedWithNoRecentTasks) {
239            if (mEmptyView == null) {
240                mEmptyView = mEmptyViewStub.inflate();
241            }
242            mEmptyView.setVisibility(View.VISIBLE);
243            mRecentsView.setSearchBarVisibility(View.GONE);
244        } else {
245            if (mEmptyView != null) {
246                mEmptyView.setVisibility(View.GONE);
247            }
248            if (mRecentsView.hasSearchBar()) {
249                mRecentsView.setSearchBarVisibility(View.VISIBLE);
250            } else {
251                addSearchBarAppWidgetView();
252            }
253        }
254
255        // Animate the SystemUI scrims into view
256        mScrimViews.prepareEnterRecentsAnimation();
257    }
258
259    /** Attempts to allocate and bind the search bar app widget */
260    void bindSearchBarAppWidget() {
261        if (Constants.DebugFlags.App.EnableSearchLayout) {
262            SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
263
264            // Reset the host view and widget info
265            mSearchAppWidgetHostView = null;
266            mSearchAppWidgetInfo = null;
267
268            // Try and load the app widget id from the settings
269            int appWidgetId = mConfig.searchBarAppWidgetId;
270            if (appWidgetId >= 0) {
271                mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId);
272                if (mSearchAppWidgetInfo == null) {
273                    // If there is no actual widget associated with that id, then delete it and
274                    // prepare to bind another app widget in its place
275                    ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
276                    appWidgetId = -1;
277                }
278            }
279
280            // If there is no id, then bind a new search app widget
281            if (appWidgetId < 0) {
282                Pair<Integer, AppWidgetProviderInfo> widgetInfo =
283                        ssp.bindSearchAppWidget(mAppWidgetHost);
284                if (widgetInfo != null) {
285                    // Save the app widget id into the settings
286                    mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first);
287                    mSearchAppWidgetInfo = widgetInfo.second;
288                }
289            }
290        }
291    }
292
293    /** Creates the search bar app widget view */
294    void addSearchBarAppWidgetView() {
295        if (Constants.DebugFlags.App.EnableSearchLayout) {
296            int appWidgetId = mConfig.searchBarAppWidgetId;
297            if (appWidgetId >= 0) {
298                mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
299                        mSearchAppWidgetInfo);
300                Bundle opts = new Bundle();
301                opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
302                        AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
303                mSearchAppWidgetHostView.updateAppWidgetOptions(opts);
304                // Set the padding to 0 for this search widget
305                mSearchAppWidgetHostView.setPadding(0, 0, 0, 0);
306                mRecentsView.setSearchBar(mSearchAppWidgetHostView);
307            } else {
308                mRecentsView.setSearchBar(null);
309            }
310        }
311    }
312
313    /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
314    boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
315        if (mVisible) {
316            // If we currently have filtered stacks, then unfilter those first
317            if (checkFilteredStackState &&
318                mRecentsView.unfilterFilteredStacks()) return true;
319            // If we have a focused Task, launch that Task now
320            if (mRecentsView.launchFocusedTask()) return true;
321            // If we launched from Home, then return to Home
322            if (mConfig.launchedFromHome) {
323                dismissRecentsToHomeRaw(true);
324                return true;
325            }
326            // Otherwise, try and return to the Task that Recents was launched from
327            if (mRecentsView.launchPreviousTask()) return true;
328            // If none of the other cases apply, then just go Home
329            dismissRecentsToHomeRaw(true);
330            return true;
331        }
332        return false;
333    }
334
335    /** Dismisses Recents directly to Home. */
336    void dismissRecentsToHomeRaw(boolean animated) {
337        if (animated) {
338            ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
339                    null, mFinishLaunchHomeRunnable, null);
340            mRecentsView.startExitToHomeAnimation(
341                    new ViewAnimation.TaskViewExitContext(exitTrigger));
342        } else {
343            mFinishLaunchHomeRunnable.run();
344        }
345    }
346
347    /** Dismisses Recents directly to Home if we currently aren't transitioning. */
348    boolean dismissRecentsToHome(boolean animated) {
349        if (mVisible) {
350            // Return to Home
351            dismissRecentsToHomeRaw(animated);
352            return true;
353        }
354        return false;
355    }
356
357    /** Called with the activity is first created. */
358    @Override
359    public void onCreate(Bundle savedInstanceState) {
360        super.onCreate(savedInstanceState);
361        // For the non-primary user, ensure that the SystemSericesProxy is initialized
362        RecentsTaskLoader.initialize(this);
363
364        // Initialize the loader and the configuration
365        mConfig = RecentsConfiguration.reinitialize(this,
366                RecentsTaskLoader.getInstance().getSystemServicesProxy());
367
368        // Initialize the widget host (the host id is static and does not change)
369        mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
370
371        // Set the Recents layout
372        setContentView(R.layout.recents);
373        mRecentsView = (RecentsView) findViewById(R.id.recents_view);
374        mRecentsView.setCallbacks(this);
375        mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
376                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
377                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
378        mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
379        mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
380        mScrimViews = new SystemBarScrimViews(this, mConfig);
381        inflateDebugOverlay();
382
383        // Bind the search app widget when we first start up
384        bindSearchBarAppWidget();
385        // Update the recent tasks
386        updateRecentsTasks(getIntent());
387
388        // Register the broadcast receiver to handle messages when the screen is turned off
389        IntentFilter filter = new IntentFilter();
390        filter.addAction(Intent.ACTION_SCREEN_OFF);
391        filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
392        registerReceiver(mSystemBroadcastReceiver, filter);
393
394        // Private API calls to make the shadows look better
395        try {
396            Utilities.setShadowProperty("ambientRatio", String.valueOf(1.5f));
397        } catch (IllegalAccessException e) {
398            e.printStackTrace();
399        } catch (InvocationTargetException e) {
400            e.printStackTrace();
401        }
402
403        // Update if we are getting a configuration change
404        if (savedInstanceState != null) {
405            mConfig.updateOnConfigurationChange();
406            onConfigurationChange();
407        }
408
409        // Start listening for widget package changes if there is one bound, post it since we don't
410        // want it stalling the startup
411        if (mConfig.searchBarAppWidgetId >= 0) {
412            final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> callback =
413                    new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>(this);
414            mRecentsView.post(new Runnable() {
415                @Override
416                public void run() {
417                    RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = callback.get();
418                    if (cb != null) {
419                        mAppWidgetHost.startListening(cb);
420                    }
421                }
422            });
423        }
424    }
425
426    /** Inflates the debug overlay if debug mode is enabled. */
427    void inflateDebugOverlay() {
428        if (mConfig.debugModeEnabled && mDebugOverlay == null) {
429            // Inflate the overlay and seek bars
430            mDebugOverlay = (DebugOverlayView) mDebugOverlayStub.inflate();
431            mDebugOverlay.setCallbacks(this);
432            mRecentsView.setDebugOverlay(mDebugOverlay);
433        }
434    }
435
436    void onConfigurationChange() {
437        // Update RecentsConfiguration
438        mConfig = RecentsConfiguration.reinitialize(this,
439                RecentsTaskLoader.getInstance().getSystemServicesProxy());
440
441        // Try and start the enter animation (or restart it on configuration changed)
442        ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
443        mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
444        onEnterAnimationTriggered();
445    }
446
447    @Override
448    protected void onNewIntent(Intent intent) {
449        super.onNewIntent(intent);
450        setIntent(intent);
451
452        // Reinitialize the configuration
453        RecentsConfiguration.reinitialize(this, RecentsTaskLoader.getInstance().getSystemServicesProxy());
454
455        // Clear any debug rects
456        if (mDebugOverlay != null) {
457            mDebugOverlay.clear();
458        }
459
460        // Update the recent tasks
461        updateRecentsTasks(intent);
462    }
463
464    @Override
465    protected void onStart() {
466        super.onStart();
467
468        // Register the broadcast receiver to handle messages from our service
469        IntentFilter filter = new IntentFilter();
470        filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY);
471        filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY);
472        filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION);
473        registerReceiver(mServiceBroadcastReceiver, filter);
474
475        // Register any broadcast receivers for the task loader
476        RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
477    }
478
479    @Override
480    protected void onResume() {
481        super.onResume();
482
483        // Mark Recents as visible
484        mVisible = true;
485    }
486
487    @Override
488    protected void onStop() {
489        super.onStop();
490
491        // Remove all the views
492        mRecentsView.removeAllTaskStacks();
493
494        // Unregister the RecentsService receiver
495        unregisterReceiver(mServiceBroadcastReceiver);
496
497        // Unregister any broadcast receivers for the task loader
498        RecentsTaskLoader.getInstance().unregisterReceivers();
499    }
500
501    @Override
502    protected void onDestroy() {
503        super.onDestroy();
504
505        // Unregister the system broadcast receivers
506        unregisterReceiver(mSystemBroadcastReceiver);
507
508        // Stop listening for widget package changes if there was one bound
509        if (mAppWidgetHost.isListening()) {
510            mAppWidgetHost.stopListening();
511        }
512    }
513
514    @Override
515    public void onTrimMemory(int level) {
516        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
517        if (loader != null) {
518            loader.onTrimMemory(level);
519        }
520    }
521
522    @Override
523    public boolean onKeyDown(int keyCode, KeyEvent event) {
524        switch (keyCode) {
525            case KeyEvent.KEYCODE_TAB: {
526                boolean hasRepKeyTimeElapsed = (System.currentTimeMillis() -
527                        mLastTabKeyEventTime) > mConfig.altTabKeyDelay;
528                if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
529                    // Focus the next task in the stack
530                    final boolean backward = event.isShiftPressed();
531                    mRecentsView.focusNextTask(!backward);
532                    mLastTabKeyEventTime = System.currentTimeMillis();
533                }
534                return true;
535            }
536            case KeyEvent.KEYCODE_DPAD_UP: {
537                mRecentsView.focusNextTask(true);
538                return true;
539            }
540            case KeyEvent.KEYCODE_DPAD_DOWN: {
541                mRecentsView.focusNextTask(false);
542                return true;
543            }
544            case KeyEvent.KEYCODE_DEL:
545            case KeyEvent.KEYCODE_FORWARD_DEL: {
546                mRecentsView.dismissFocusedTask();
547                return true;
548            }
549            default:
550                break;
551        }
552        // Pass through the debug trigger
553        mDebugTrigger.onKeyEvent(keyCode);
554        return super.onKeyDown(keyCode, event);
555    }
556
557    @Override
558    public void onUserInteraction() {
559        mRecentsView.onUserInteraction();
560    }
561
562    @Override
563    public void onBackPressed() {
564        // Test mode where back does not do anything
565        if (mConfig.debugModeEnabled) return;
566
567        // Dismiss Recents to the focused Task or Home
568        dismissRecentsToFocusedTaskOrHome(true);
569    }
570
571    /** Called when debug mode is triggered */
572    public void onDebugModeTriggered() {
573
574        if (mConfig.developerOptionsEnabled) {
575            SharedPreferences settings = getSharedPreferences(getPackageName(), 0);
576            if (settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false)) {
577                // Disable the debug mode
578                settings.edit().remove(Constants.Values.App.Key_DebugModeEnabled).apply();
579                mConfig.debugModeEnabled = false;
580                inflateDebugOverlay();
581                mDebugOverlay.disable();
582            } else {
583                // Enable the debug mode
584                settings.edit().putBoolean(Constants.Values.App.Key_DebugModeEnabled, true).apply();
585                mConfig.debugModeEnabled = true;
586                inflateDebugOverlay();
587                mDebugOverlay.enable();
588            }
589            Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " +
590                (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now",
591                Toast.LENGTH_SHORT).show();
592        }
593    }
594
595    /** Called when the enter recents animation is triggered. */
596    public void onEnterAnimationTriggered() {
597        // Animate the SystemUI scrim views
598        mScrimViews.startEnterRecentsAnimation();
599    }
600
601    /**** RecentsView.RecentsViewCallbacks Implementation ****/
602
603    @Override
604    public void onExitToHomeAnimationTriggered() {
605        // Animate the SystemUI scrim views out
606        mScrimViews.startExitRecentsAnimation();
607    }
608
609    @Override
610    public void onTaskViewClicked() {
611        // Mark recents as no longer visible
612        AlternateRecentsComponent.notifyVisibilityChanged(false);
613        mVisible = false;
614    }
615
616    @Override
617    public void onTaskLaunchFailed() {
618        // Return to Home
619        dismissRecentsToHomeRaw(true);
620    }
621
622    @Override
623    public void onAllTaskViewsDismissed() {
624        mFinishLaunchHomeRunnable.run();
625    }
626
627    /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/
628
629    @Override
630    public void refreshSearchWidget() {
631        bindSearchBarAppWidget();
632        addSearchBarAppWidgetView();
633    }
634
635    /**** DebugOverlayView.DebugOverlayViewCallbacks ****/
636
637    @Override
638    public void onPrimarySeekBarChanged(float progress) {
639        // Do nothing
640    }
641
642    @Override
643    public void onSecondarySeekBarChanged(float progress) {
644        // Do nothing
645    }
646}
647