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