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 long mLastTabKeyEventTime; 69 70 // Top level views 71 RecentsView mRecentsView; 72 SystemBarScrimViews mScrimViews; 73 ViewStub mEmptyViewStub; 74 ViewStub mDebugOverlayStub; 75 View mEmptyView; 76 DebugOverlayView mDebugOverlay; 77 78 // Search AppWidget 79 RecentsAppWidgetHost mAppWidgetHost; 80 AppWidgetProviderInfo mSearchAppWidgetInfo; 81 AppWidgetHostView mSearchAppWidgetHostView; 82 83 // Runnables to finish the Recents activity 84 FinishRecentsRunnable mFinishLaunchHomeRunnable; 85 86 private PhoneStatusBar mStatusBar; 87 88 /** 89 * A common Runnable to finish Recents either by calling finish() (with a custom animation) or 90 * launching Home with some ActivityOptions. Generally we always launch home when we exit 91 * Recents rather than just finishing the activity since we don't know what is behind Recents in 92 * the task stack. The only case where we finish() directly is when we are cancelling the full 93 * screen transition from the app. 94 */ 95 class FinishRecentsRunnable implements Runnable { 96 Intent mLaunchIntent; 97 ActivityOptions mLaunchOpts; 98 99 /** 100 * Creates a finish runnable that starts the specified intent, using the given 101 * ActivityOptions. 102 */ 103 public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) { 104 mLaunchIntent = launchIntent; 105 mLaunchOpts = opts; 106 } 107 108 @Override 109 public void run() { 110 // Finish Recents 111 if (mLaunchIntent != null) { 112 if (mLaunchOpts != null) { 113 startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT); 114 } else { 115 startActivityAsUser(mLaunchIntent, UserHandle.CURRENT); 116 } 117 } else { 118 finish(); 119 overridePendingTransition(R.anim.recents_to_launcher_enter, 120 R.anim.recents_to_launcher_exit); 121 } 122 } 123 } 124 125 /** 126 * Broadcast receiver to handle messages from AlternateRecentsComponent. 127 */ 128 final BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() { 129 @Override 130 public void onReceive(Context context, Intent intent) { 131 String action = intent.getAction(); 132 if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) { 133 if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) { 134 // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app 135 dismissRecentsToFocusedTaskOrHome(false); 136 } else if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) { 137 // Otherwise, dismiss Recents to Home 138 dismissRecentsToHome(true); 139 } else { 140 // Do nothing, another activity is being launched on top of Recents 141 } 142 } else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) { 143 // If we are toggling Recents, then first unfilter any filtered stacks first 144 dismissRecentsToFocusedTaskOrHome(true); 145 } else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) { 146 // Trigger the enter animation 147 onEnterAnimationTriggered(); 148 // Notify the fallback receiver that we have successfully got the broadcast 149 // See AlternateRecentsComponent.onAnimationStarted() 150 setResultCode(Activity.RESULT_OK); 151 } 152 } 153 }; 154 155 /** 156 * Broadcast receiver to handle messages from the system 157 */ 158 final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() { 159 @Override 160 public void onReceive(Context context, Intent intent) { 161 String action = intent.getAction(); 162 if (action.equals(Intent.ACTION_SCREEN_OFF)) { 163 // When the screen turns off, dismiss Recents to Home 164 dismissRecentsToHome(false); 165 } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) { 166 // When the search activity changes, update the Search widget 167 refreshSearchWidget(); 168 } 169 } 170 }; 171 172 /** 173 * A custom debug trigger to listen for a debug key chord. 174 */ 175 final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() { 176 @Override 177 public void run() { 178 onDebugModeTriggered(); 179 } 180 }); 181 182 /** Updates the set of recent tasks */ 183 void updateRecentsTasks(Intent launchIntent) { 184 // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent 185 // reconstructing the task stack 186 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 187 RecentsTaskLoadPlan plan = AlternateRecentsComponent.consumeInstanceLoadPlan(); 188 if (plan == null) { 189 plan = loader.createLoadPlan(this); 190 } 191 192 // Start loading tasks according to the load plan 193 if (plan.getTaskStack() == null) { 194 loader.preloadTasks(plan, mConfig.launchedFromHome); 195 } 196 RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); 197 loadOpts.runningTaskId = mConfig.launchedToTaskId; 198 loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks; 199 loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails; 200 loader.loadTasks(this, plan, loadOpts); 201 202 SpaceNode root = plan.getSpaceNode(); 203 ArrayList<TaskStack> stacks = root.getStacks(); 204 boolean hasTasks = root.hasTasks(); 205 if (hasTasks) { 206 mRecentsView.setTaskStacks(stacks); 207 } 208 mConfig.launchedWithNoRecentTasks = !hasTasks; 209 210 // Create the home intent runnable 211 Intent homeIntent = new Intent(Intent.ACTION_MAIN, null); 212 homeIntent.addCategory(Intent.CATEGORY_HOME); 213 homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 214 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 215 mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, 216 ActivityOptions.makeCustomAnimation(this, 217 mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter : 218 R.anim.recents_to_launcher_enter, 219 mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit : 220 R.anim.recents_to_launcher_exit)); 221 222 // Mark the task that is the launch target 223 int taskStackCount = stacks.size(); 224 if (mConfig.launchedToTaskId != -1) { 225 for (int i = 0; i < taskStackCount; i++) { 226 TaskStack stack = stacks.get(i); 227 ArrayList<Task> tasks = stack.getTasks(); 228 int taskCount = tasks.size(); 229 for (int j = 0; j < taskCount; j++) { 230 Task t = tasks.get(j); 231 if (t.key.id == mConfig.launchedToTaskId) { 232 t.isLaunchTarget = true; 233 break; 234 } 235 } 236 } 237 } 238 239 // Update the top level view's visibilities 240 if (mConfig.launchedWithNoRecentTasks) { 241 if (mEmptyView == null) { 242 mEmptyView = mEmptyViewStub.inflate(); 243 } 244 mEmptyView.setVisibility(View.VISIBLE); 245 mRecentsView.setSearchBarVisibility(View.GONE); 246 } else { 247 if (mEmptyView != null) { 248 mEmptyView.setVisibility(View.GONE); 249 } 250 if (mRecentsView.hasSearchBar()) { 251 mRecentsView.setSearchBarVisibility(View.VISIBLE); 252 } else { 253 addSearchBarAppWidgetView(); 254 } 255 } 256 257 // Animate the SystemUI scrims into view 258 mScrimViews.prepareEnterRecentsAnimation(); 259 } 260 261 /** Attempts to allocate and bind the search bar app widget */ 262 void bindSearchBarAppWidget() { 263 if (Constants.DebugFlags.App.EnableSearchLayout) { 264 SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); 265 266 // Reset the host view and widget info 267 mSearchAppWidgetHostView = null; 268 mSearchAppWidgetInfo = null; 269 270 // Try and load the app widget id from the settings 271 int appWidgetId = mConfig.searchBarAppWidgetId; 272 if (appWidgetId >= 0) { 273 mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId); 274 if (mSearchAppWidgetInfo == null) { 275 // If there is no actual widget associated with that id, then delete it and 276 // prepare to bind another app widget in its place 277 ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId); 278 appWidgetId = -1; 279 } 280 } 281 282 // If there is no id, then bind a new search app widget 283 if (appWidgetId < 0) { 284 Pair<Integer, AppWidgetProviderInfo> widgetInfo = 285 ssp.bindSearchAppWidget(mAppWidgetHost); 286 if (widgetInfo != null) { 287 // Save the app widget id into the settings 288 mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first); 289 mSearchAppWidgetInfo = widgetInfo.second; 290 } 291 } 292 } 293 } 294 295 /** Creates the search bar app widget view */ 296 void addSearchBarAppWidgetView() { 297 if (Constants.DebugFlags.App.EnableSearchLayout) { 298 int appWidgetId = mConfig.searchBarAppWidgetId; 299 if (appWidgetId >= 0) { 300 mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId, 301 mSearchAppWidgetInfo); 302 Bundle opts = new Bundle(); 303 opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 304 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); 305 mSearchAppWidgetHostView.updateAppWidgetOptions(opts); 306 // Set the padding to 0 for this search widget 307 mSearchAppWidgetHostView.setPadding(0, 0, 0, 0); 308 mRecentsView.setSearchBar(mSearchAppWidgetHostView); 309 } else { 310 mRecentsView.setSearchBar(null); 311 } 312 } 313 } 314 315 /** Dismisses recents if we are already visible and the intent is to toggle the recents view */ 316 boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) { 317 SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); 318 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 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 SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); 353 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 354 // Return to Home 355 dismissRecentsToHomeRaw(animated); 356 return true; 357 } 358 return false; 359 } 360 361 /** Called with the activity is first created. */ 362 @Override 363 public void onCreate(Bundle savedInstanceState) { 364 super.onCreate(savedInstanceState); 365 // For the non-primary user, ensure that the SystemServicesProxy and configuration is 366 // initialized 367 RecentsTaskLoader.initialize(this); 368 SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); 369 mConfig = RecentsConfiguration.reinitialize(this, ssp); 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 // Clear any debug rects 425 if (mDebugOverlay != null) { 426 mDebugOverlay.clear(); 427 } 428 } 429 430 @Override 431 protected void onStart() { 432 super.onStart(); 433 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 434 SystemServicesProxy ssp = loader.getSystemServicesProxy(); 435 AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, true); 436 437 // Register the broadcast receiver to handle messages from our service 438 IntentFilter filter = new IntentFilter(); 439 filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY); 440 filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY); 441 filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION); 442 registerReceiver(mServiceBroadcastReceiver, filter); 443 444 // Register any broadcast receivers for the task loader 445 loader.registerReceivers(this, mRecentsView); 446 447 // Update the recent tasks 448 updateRecentsTasks(getIntent()); 449 450 // If this is a new instance from a configuration change, then we have to manually trigger 451 // the enter animation state 452 if (mConfig.launchedHasConfigurationChanged) { 453 onEnterAnimationTriggered(); 454 } 455 } 456 457 @Override 458 protected void onStop() { 459 super.onStop(); 460 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 461 SystemServicesProxy ssp = loader.getSystemServicesProxy(); 462 AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, false); 463 464 // Notify the views that we are no longer visible 465 mRecentsView.onRecentsHidden(); 466 467 // Unregister the RecentsService receiver 468 unregisterReceiver(mServiceBroadcastReceiver); 469 470 // Unregister any broadcast receivers for the task loader 471 loader.unregisterReceivers(); 472 } 473 474 @Override 475 protected void onDestroy() { 476 super.onDestroy(); 477 478 // Unregister the system broadcast receivers 479 unregisterReceiver(mSystemBroadcastReceiver); 480 481 // Stop listening for widget package changes if there was one bound 482 mAppWidgetHost.stopListening(); 483 } 484 485 public void onEnterAnimationTriggered() { 486 // Try and start the enter animation (or restart it on configuration changed) 487 ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); 488 ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t); 489 mRecentsView.startEnterRecentsAnimation(ctx); 490 if (mConfig.searchBarAppWidgetId >= 0) { 491 final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> cbRef = 492 new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>( 493 RecentsActivity.this); 494 ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { 495 @Override 496 public void run() { 497 // Start listening for widget package changes if there is one bound 498 RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = cbRef.get(); 499 if (cb != null) { 500 mAppWidgetHost.startListening(cb); 501 } 502 } 503 }); 504 } 505 506 // Animate the SystemUI scrim views 507 mScrimViews.startEnterRecentsAnimation(); 508 } 509 510 @Override 511 public void onTrimMemory(int level) { 512 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 513 if (loader != null) { 514 loader.onTrimMemory(level); 515 } 516 } 517 518 @Override 519 public boolean onKeyDown(int keyCode, KeyEvent event) { 520 switch (keyCode) { 521 case KeyEvent.KEYCODE_TAB: { 522 boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() - 523 mLastTabKeyEventTime) > mConfig.altTabKeyDelay; 524 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) { 525 // Focus the next task in the stack 526 final boolean backward = event.isShiftPressed(); 527 mRecentsView.focusNextTask(!backward); 528 mLastTabKeyEventTime = SystemClock.elapsedRealtime(); 529 } 530 return true; 531 } 532 case KeyEvent.KEYCODE_DPAD_UP: { 533 mRecentsView.focusNextTask(true); 534 return true; 535 } 536 case KeyEvent.KEYCODE_DPAD_DOWN: { 537 mRecentsView.focusNextTask(false); 538 return true; 539 } 540 case KeyEvent.KEYCODE_DEL: 541 case KeyEvent.KEYCODE_FORWARD_DEL: { 542 mRecentsView.dismissFocusedTask(); 543 return true; 544 } 545 default: 546 break; 547 } 548 // Pass through the debug trigger 549 mDebugTrigger.onKeyEvent(keyCode); 550 return super.onKeyDown(keyCode, event); 551 } 552 553 @Override 554 public void onUserInteraction() { 555 mRecentsView.onUserInteraction(); 556 } 557 558 @Override 559 public void onBackPressed() { 560 // Test mode where back does not do anything 561 if (mConfig.debugModeEnabled) return; 562 563 // Dismiss Recents to the focused Task or Home 564 dismissRecentsToFocusedTaskOrHome(true); 565 } 566 567 /** Called when debug mode is triggered */ 568 public void onDebugModeTriggered() { 569 if (mConfig.developerOptionsEnabled) { 570 SharedPreferences settings = getSharedPreferences(getPackageName(), 0); 571 if (settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false)) { 572 // Disable the debug mode 573 settings.edit().remove(Constants.Values.App.Key_DebugModeEnabled).apply(); 574 mConfig.debugModeEnabled = false; 575 inflateDebugOverlay(); 576 if (mDebugOverlay != null) { 577 mDebugOverlay.disable(); 578 } 579 } else { 580 // Enable the debug mode 581 settings.edit().putBoolean(Constants.Values.App.Key_DebugModeEnabled, true).apply(); 582 mConfig.debugModeEnabled = true; 583 inflateDebugOverlay(); 584 if (mDebugOverlay != null) { 585 mDebugOverlay.enable(); 586 } 587 } 588 Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " + 589 (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now", 590 Toast.LENGTH_SHORT).show(); 591 } 592 } 593 594 /**** RecentsView.RecentsViewCallbacks Implementation ****/ 595 596 @Override 597 public void onExitToHomeAnimationTriggered() { 598 // Animate the SystemUI scrim views out 599 mScrimViews.startExitRecentsAnimation(); 600 } 601 602 @Override 603 public void onTaskViewClicked() { 604 } 605 606 @Override 607 public void onTaskLaunchFailed() { 608 // Return to Home 609 dismissRecentsToHomeRaw(true); 610 } 611 612 @Override 613 public void onAllTaskViewsDismissed() { 614 mFinishLaunchHomeRunnable.run(); 615 } 616 617 @Override 618 public void onScreenPinningRequest() { 619 if (mStatusBar != null) { 620 mStatusBar.showScreenPinningRequest(false); 621 } 622 } 623 624 /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/ 625 626 @Override 627 public void refreshSearchWidget() { 628 bindSearchBarAppWidget(); 629 addSearchBarAppWidgetView(); 630 } 631 632 /**** DebugOverlayView.DebugOverlayViewCallbacks ****/ 633 634 @Override 635 public void onPrimarySeekBarChanged(float progress) { 636 // Do nothing 637 } 638 639 @Override 640 public void onSecondarySeekBarChanged(float progress) { 641 // Do nothing 642 } 643} 644