RecentsActivity.java revision 619e40cd56266a362ab7da80cb9e4eba6c33b204
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.TaskStackBuilder; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.res.Configuration; 27import android.net.Uri; 28import android.os.Bundle; 29import android.os.SystemClock; 30import android.os.UserHandle; 31import android.provider.Settings; 32import android.util.Log; 33import android.view.KeyEvent; 34import android.view.View; 35import android.view.ViewTreeObserver; 36import android.view.WindowManager; 37import android.view.WindowManager.LayoutParams; 38 39import com.android.internal.logging.MetricsLogger; 40import com.android.internal.logging.MetricsProto.MetricsEvent; 41import com.android.systemui.R; 42import com.android.systemui.recents.events.EventBus; 43import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; 44import com.android.systemui.recents.events.activity.ConfigurationChangedEvent; 45import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent; 46import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; 47import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; 48import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; 49import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; 50import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent; 51import com.android.systemui.recents.events.activity.HideRecentsEvent; 52import com.android.systemui.recents.events.activity.IterateRecentsEvent; 53import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent; 54import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent; 55import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent; 56import com.android.systemui.recents.events.activity.ToggleRecentsEvent; 57import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 58import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; 59import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent; 60import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; 61import com.android.systemui.recents.events.ui.RecentsDrawnEvent; 62import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; 63import com.android.systemui.recents.events.ui.StackViewScrolledEvent; 64import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent; 65import com.android.systemui.recents.events.ui.UserInteractionEvent; 66import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; 67import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; 68import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; 69import com.android.systemui.recents.misc.DozeTrigger; 70import com.android.systemui.recents.misc.SystemServicesProxy; 71import com.android.systemui.recents.model.RecentsPackageMonitor; 72import com.android.systemui.recents.model.RecentsTaskLoadPlan; 73import com.android.systemui.recents.model.RecentsTaskLoader; 74import com.android.systemui.recents.model.Task; 75import com.android.systemui.recents.model.TaskStack; 76import com.android.systemui.recents.views.AnimationProps; 77import com.android.systemui.recents.views.RecentsView; 78import com.android.systemui.recents.views.SystemBarScrimViews; 79import com.android.systemui.statusbar.BaseStatusBar; 80 81/** 82 * The main Recents activity that is started from AlternateRecentsComponent. 83 */ 84public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { 85 86 private final static String TAG = "RecentsActivity"; 87 private final static boolean DEBUG = false; 88 89 public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1; 90 91 private RecentsPackageMonitor mPackageMonitor; 92 private long mLastTabKeyEventTime; 93 private boolean mFinishedOnStartup; 94 private boolean mIgnoreAltTabRelease; 95 private boolean mIsVisible; 96 97 // Top level views 98 private RecentsView mRecentsView; 99 private SystemBarScrimViews mScrimViews; 100 101 // Runnables to finish the Recents activity 102 private Intent mHomeIntent; 103 104 // The trigger to automatically launch the current task 105 private int mFocusTimerDuration; 106 private DozeTrigger mIterateTrigger; 107 private final UserInteractionEvent mUserInteractionEvent = new UserInteractionEvent(); 108 109 /** 110 * A common Runnable to finish Recents by launching Home with an animation depending on the 111 * last activity launch state. Generally we always launch home when we exit Recents rather than 112 * just finishing the activity since we don't know what is behind Recents in the task stack. 113 */ 114 class LaunchHomeRunnable implements Runnable { 115 116 Intent mLaunchIntent; 117 ActivityOptions mOpts; 118 119 /** 120 * Creates a finish runnable that starts the specified intent. 121 */ 122 public LaunchHomeRunnable(Intent launchIntent, ActivityOptions opts) { 123 mLaunchIntent = launchIntent; 124 mOpts = opts; 125 } 126 127 @Override 128 public void run() { 129 try { 130 ActivityOptions opts = mOpts; 131 if (opts == null) { 132 opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this, 133 R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit); 134 } 135 startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT); 136 } catch (Exception e) { 137 Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e); 138 } 139 } 140 } 141 142 /** 143 * Broadcast receiver to handle messages from the system 144 */ 145 final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() { 146 @Override 147 public void onReceive(Context context, Intent intent) { 148 String action = intent.getAction(); 149 if (action.equals(Intent.ACTION_SCREEN_OFF)) { 150 // When the screen turns off, dismiss Recents to Home 151 dismissRecentsToHomeIfVisible(false); 152 } 153 } 154 }; 155 156 /** 157 * Dismisses recents if we are already visible and the intent is to toggle the recents view. 158 */ 159 boolean dismissRecentsToFocusedTask(int logCategory) { 160 SystemServicesProxy ssp = Recents.getSystemServices(); 161 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 162 // If we have a focused Task, launch that Task now 163 if (mRecentsView.launchFocusedTask(logCategory)) return true; 164 } 165 return false; 166 } 167 168 /** 169 * Dismisses recents back to the launch target task. 170 */ 171 boolean dismissRecentsToLaunchTargetTaskOrHome() { 172 SystemServicesProxy ssp = Recents.getSystemServices(); 173 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 174 // If we have a focused Task, launch that Task now 175 if (mRecentsView.launchPreviousTask()) return true; 176 // If none of the other cases apply, then just go Home 177 dismissRecentsToHome(true /* animateTaskViews */); 178 } 179 return false; 180 } 181 182 /** 183 * Dismisses recents if we are already visible and the intent is to toggle the recents view. 184 */ 185 boolean dismissRecentsToFocusedTaskOrHome() { 186 SystemServicesProxy ssp = Recents.getSystemServices(); 187 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 188 // If we have a focused Task, launch that Task now 189 if (mRecentsView.launchFocusedTask(0 /* logCategory */)) return true; 190 // If none of the other cases apply, then just go Home 191 dismissRecentsToHome(true /* animateTaskViews */); 192 return true; 193 } 194 return false; 195 } 196 197 /** 198 * Dismisses Recents directly to Home without checking whether it is currently visible. 199 */ 200 void dismissRecentsToHome(boolean animateTaskViews) { 201 dismissRecentsToHome(animateTaskViews, null); 202 } 203 204 /** 205 * Dismisses Recents directly to Home without checking whether it is currently visible. 206 * 207 * @param overrideAnimation If not null, will override the default animation that is based on 208 * how Recents was launched. 209 */ 210 void dismissRecentsToHome(boolean animateTaskViews, ActivityOptions overrideAnimation) { 211 DismissRecentsToHomeAnimationStarted dismissEvent = 212 new DismissRecentsToHomeAnimationStarted(animateTaskViews); 213 dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent, 214 overrideAnimation)); 215 dismissEvent.addPostAnimationCallback(new Runnable() { 216 @Override 217 public void run() { 218 Recents.getSystemServices().sendCloseSystemWindows( 219 BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY); 220 } 221 }); 222 EventBus.getDefault().send(dismissEvent); 223 } 224 225 /** Dismisses Recents directly to Home if we currently aren't transitioning. */ 226 boolean dismissRecentsToHomeIfVisible(boolean animated) { 227 SystemServicesProxy ssp = Recents.getSystemServices(); 228 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 229 // Return to Home 230 dismissRecentsToHome(animated); 231 return true; 232 } 233 return false; 234 } 235 236 /** Called with the activity is first created. */ 237 @Override 238 public void onCreate(Bundle savedInstanceState) { 239 super.onCreate(savedInstanceState); 240 mFinishedOnStartup = false; 241 242 // In the case that the activity starts up before the Recents component has initialized 243 // (usually when debugging/pushing the SysUI apk), just finish this activity. 244 SystemServicesProxy ssp = Recents.getSystemServices(); 245 if (ssp == null) { 246 mFinishedOnStartup = true; 247 finish(); 248 return; 249 } 250 251 // Register this activity with the event bus 252 EventBus.getDefault().register(this, EVENT_BUS_PRIORITY); 253 254 // Initialize the package monitor 255 mPackageMonitor = new RecentsPackageMonitor(); 256 mPackageMonitor.register(this); 257 258 // Set the Recents layout 259 setContentView(R.layout.recents); 260 takeKeyEvents(true); 261 mRecentsView = (RecentsView) findViewById(R.id.recents_view); 262 mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | 263 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 264 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 265 mScrimViews = new SystemBarScrimViews(this); 266 getWindow().getAttributes().privateFlags |= 267 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; 268 269 mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration); 270 mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() { 271 @Override 272 public void run() { 273 dismissRecentsToFocusedTask(MetricsEvent.OVERVIEW_SELECT_TIMEOUT); 274 } 275 }); 276 277 // Create the home intent runnable 278 mHomeIntent = new Intent(Intent.ACTION_MAIN, null); 279 mHomeIntent.addCategory(Intent.CATEGORY_HOME); 280 mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 281 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 282 283 // Register the broadcast receiver to handle messages when the screen is turned off 284 IntentFilter filter = new IntentFilter(); 285 filter.addAction(Intent.ACTION_SCREEN_OFF); 286 registerReceiver(mSystemBroadcastReceiver, filter); 287 288 getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION); 289 290 // Reload the stack view 291 reloadStackView(); 292 } 293 294 @Override 295 protected void onStart() { 296 super.onStart(); 297 298 // Notify that recents is now visible 299 EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true)); 300 MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY); 301 } 302 303 @Override 304 protected void onNewIntent(Intent intent) { 305 super.onNewIntent(intent); 306 307 // Reload the stack view 308 reloadStackView(); 309 } 310 311 /** 312 * Reloads the stack views upon launching Recents. 313 */ 314 private void reloadStackView() { 315 // If the Recents component has preloaded a load plan, then use that to prevent 316 // reconstructing the task stack 317 RecentsTaskLoader loader = Recents.getTaskLoader(); 318 RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan(); 319 if (loadPlan == null) { 320 loadPlan = loader.createLoadPlan(this); 321 } 322 323 // Start loading tasks according to the load plan 324 RecentsConfiguration config = Recents.getConfiguration(); 325 RecentsActivityLaunchState launchState = config.getLaunchState(); 326 if (!loadPlan.hasTasks()) { 327 loader.preloadTasks(loadPlan, launchState.launchedToTaskId, 328 launchState.launchedFromHome); 329 } 330 331 RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); 332 loadOpts.runningTaskId = launchState.launchedToTaskId; 333 loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; 334 loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; 335 loader.loadTasks(this, loadPlan, loadOpts); 336 TaskStack stack = loadPlan.getTaskStack(); 337 mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0); 338 mRecentsView.updateStack(stack); 339 340 // Update the nav bar scrim, but defer the animation until the enter-window event 341 boolean animateNavBarScrim = !launchState.launchedWhileDocking; 342 updateNavBarScrim(animateNavBarScrim, null); 343 344 // If this is a new instance relaunched by AM, without going through the normal mechanisms, 345 // then we have to manually trigger the enter animation state 346 boolean wasLaunchedByAm = !launchState.launchedFromHome && 347 !launchState.launchedFromApp; 348 if (wasLaunchedByAm) { 349 EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent()); 350 } 351 352 // Keep track of whether we launched from the nav bar button or via alt-tab 353 if (launchState.launchedWithAltTab) { 354 MetricsLogger.count(this, "overview_trigger_alttab", 1); 355 } else { 356 MetricsLogger.count(this, "overview_trigger_nav_btn", 1); 357 } 358 359 // Keep track of whether we launched from an app or from home 360 if (launchState.launchedFromApp) { 361 Task launchTarget = stack.getLaunchTarget(); 362 int launchTaskIndexInStack = launchTarget != null 363 ? stack.indexOfStackTask(launchTarget) 364 : 0; 365 MetricsLogger.count(this, "overview_source_app", 1); 366 // If from an app, track the stack index of the app in the stack (for affiliated tasks) 367 MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack); 368 } else { 369 MetricsLogger.count(this, "overview_source_home", 1); 370 } 371 372 // Keep track of the total stack task count 373 int taskCount = mRecentsView.getStack().getTaskCount(); 374 MetricsLogger.histogram(this, "overview_task_count", taskCount); 375 376 // After we have resumed, set the visible state until the next onStop() call 377 mIsVisible = true; 378 } 379 380 @Override 381 public void onEnterAnimationComplete() { 382 super.onEnterAnimationComplete(); 383 EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent()); 384 } 385 386 @Override 387 protected void onResume() { 388 super.onResume(); 389 390 // Notify of the next draw 391 mRecentsView.getViewTreeObserver().addOnPreDrawListener( 392 new ViewTreeObserver.OnPreDrawListener() { 393 394 @Override 395 public boolean onPreDraw() { 396 mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this); 397 EventBus.getDefault().post(new RecentsDrawnEvent()); 398 return true; 399 } 400 }); 401 } 402 403 @Override 404 protected void onPause() { 405 super.onPause(); 406 407 mIgnoreAltTabRelease = false; 408 mIterateTrigger.stopDozing(); 409 } 410 411 @Override 412 public void onConfigurationChanged(Configuration newConfig) { 413 super.onConfigurationChanged(newConfig); 414 415 // Update the nav bar for the current orientation 416 updateNavBarScrim(false /* animateNavBarScrim */, AnimationProps.IMMEDIATE); 417 418 EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */)); 419 } 420 421 @Override 422 public void onMultiWindowChanged(boolean inMultiWindow) { 423 super.onMultiWindowChanged(inMultiWindow); 424 EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */)); 425 426 if (mRecentsView != null) { 427 // Reload the task stack completely 428 RecentsConfiguration config = Recents.getConfiguration(); 429 RecentsActivityLaunchState launchState = config.getLaunchState(); 430 RecentsTaskLoader loader = Recents.getTaskLoader(); 431 RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this); 432 loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */); 433 434 RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); 435 loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; 436 loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; 437 loader.loadTasks(this, loadPlan, loadOpts); 438 439 mRecentsView.updateStack(loadPlan.getTaskStack()); 440 } 441 442 EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow)); 443 } 444 445 @Override 446 protected void onStop() { 447 super.onStop(); 448 449 // Notify that recents is now hidden 450 mIsVisible = false; 451 EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false)); 452 MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY); 453 454 // Workaround for b/22542869, if the RecentsActivity is started again, but without going 455 // through SystemUI, we need to reset the config launch flags to ensure that we do not 456 // wait on the system to send a signal that was never queued. 457 RecentsConfiguration config = Recents.getConfiguration(); 458 RecentsActivityLaunchState launchState = config.getLaunchState(); 459 launchState.reset(); 460 } 461 462 @Override 463 protected void onDestroy() { 464 super.onDestroy(); 465 466 // In the case that the activity finished on startup, just skip the unregistration below 467 if (mFinishedOnStartup) { 468 return; 469 } 470 471 // Unregister the system broadcast receivers 472 unregisterReceiver(mSystemBroadcastReceiver); 473 474 // Unregister any broadcast receivers for the task loader 475 mPackageMonitor.unregister(); 476 477 EventBus.getDefault().unregister(this); 478 } 479 480 @Override 481 public void onAttachedToWindow() { 482 super.onAttachedToWindow(); 483 EventBus.getDefault().register(mScrimViews, EVENT_BUS_PRIORITY); 484 } 485 486 @Override 487 public void onDetachedFromWindow() { 488 super.onDetachedFromWindow(); 489 EventBus.getDefault().unregister(mScrimViews); 490 } 491 492 @Override 493 public void onTrimMemory(int level) { 494 RecentsTaskLoader loader = Recents.getTaskLoader(); 495 if (loader != null) { 496 loader.onTrimMemory(level); 497 } 498 } 499 500 @Override 501 public boolean onKeyDown(int keyCode, KeyEvent event) { 502 switch (keyCode) { 503 case KeyEvent.KEYCODE_TAB: { 504 int altTabKeyDelay = getResources().getInteger(R.integer.recents_alt_tab_key_delay); 505 boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() - 506 mLastTabKeyEventTime) > altTabKeyDelay; 507 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) { 508 // Focus the next task in the stack 509 final boolean backward = event.isShiftPressed(); 510 if (backward) { 511 EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); 512 } else { 513 EventBus.getDefault().send( 514 new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */)); 515 } 516 mLastTabKeyEventTime = SystemClock.elapsedRealtime(); 517 518 // In the case of another ALT event, don't ignore the next release 519 if (event.isAltPressed()) { 520 mIgnoreAltTabRelease = false; 521 } 522 } 523 return true; 524 } 525 case KeyEvent.KEYCODE_DPAD_UP: { 526 EventBus.getDefault().send( 527 new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */)); 528 return true; 529 } 530 case KeyEvent.KEYCODE_DPAD_DOWN: { 531 EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); 532 return true; 533 } 534 case KeyEvent.KEYCODE_DEL: 535 case KeyEvent.KEYCODE_FORWARD_DEL: { 536 if (event.getRepeatCount() <= 0) { 537 EventBus.getDefault().send(new DismissFocusedTaskViewEvent()); 538 539 // Keep track of deletions by keyboard 540 MetricsLogger.histogram(this, "overview_task_dismissed_source", 541 Constants.Metrics.DismissSourceKeyboard); 542 return true; 543 } 544 } 545 default: 546 break; 547 } 548 return super.onKeyDown(keyCode, event); 549 } 550 551 @Override 552 public void onUserInteraction() { 553 EventBus.getDefault().send(mUserInteractionEvent); 554 } 555 556 @Override 557 public void onBackPressed() { 558 // Back behaves like the recents button so just trigger a toggle event 559 EventBus.getDefault().send(new ToggleRecentsEvent()); 560 } 561 562 /**** EventBus events ****/ 563 564 public final void onBusEvent(ToggleRecentsEvent event) { 565 RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); 566 if (launchState.launchedFromHome) { 567 dismissRecentsToHome(true /* animateTaskViews */); 568 } else { 569 dismissRecentsToLaunchTargetTaskOrHome(); 570 } 571 } 572 573 public final void onBusEvent(IterateRecentsEvent event) { 574 final RecentsDebugFlags debugFlags = Recents.getDebugFlags(); 575 576 // Start dozing after the recents button is clicked 577 int timerIndicatorDuration = 0; 578 if (debugFlags.isFastToggleRecentsEnabled()) { 579 timerIndicatorDuration = getResources().getInteger( 580 R.integer.recents_subsequent_auto_advance_duration); 581 582 mIterateTrigger.setDozeDuration(timerIndicatorDuration); 583 if (!mIterateTrigger.isDozing()) { 584 mIterateTrigger.startDozing(); 585 } else { 586 mIterateTrigger.poke(); 587 } 588 } 589 590 // Focus the next task 591 EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration)); 592 593 MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE); 594 } 595 596 public final void onBusEvent(UserInteractionEvent event) { 597 // Stop the fast-toggle dozer 598 mIterateTrigger.stopDozing(); 599 } 600 601 public final void onBusEvent(HideRecentsEvent event) { 602 if (event.triggeredFromAltTab) { 603 // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app 604 if (!mIgnoreAltTabRelease) { 605 dismissRecentsToFocusedTaskOrHome(); 606 } 607 } else if (event.triggeredFromHomeKey) { 608 dismissRecentsToHome(true /* animateTaskViews */); 609 610 // Cancel any pending dozes 611 EventBus.getDefault().send(mUserInteractionEvent); 612 } else { 613 // Do nothing 614 } 615 } 616 617 public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) { 618 EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true)); 619 mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); 620 mRecentsView.invalidate(); 621 } 622 623 public final void onBusEvent(ExitRecentsWindowFirstAnimationFrameEvent event) { 624 if (mRecentsView.isLastTaskLaunchedFreeform()) { 625 EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(false)); 626 } 627 mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); 628 mRecentsView.invalidate(); 629 } 630 631 public final void onBusEvent(DockedFirstAnimationFrameEvent event) { 632 mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); 633 mRecentsView.invalidate(); 634 } 635 636 public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) { 637 RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); 638 int launchToTaskId = launchState.launchedToTaskId; 639 if (launchToTaskId != -1 && 640 (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) { 641 SystemServicesProxy ssp = Recents.getSystemServices(); 642 ssp.cancelWindowTransition(launchState.launchedToTaskId); 643 ssp.cancelThumbnailTransition(getTaskId()); 644 } 645 } 646 647 public final void onBusEvent(ShowApplicationInfoEvent event) { 648 // Create a new task stack with the application info details activity 649 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 650 Uri.fromParts("package", event.task.key.getComponent().getPackageName(), null)); 651 intent.setComponent(intent.resolveActivity(getPackageManager())); 652 TaskStackBuilder.create(this) 653 .addNextIntentWithParentStack(intent).startActivities(null, 654 new UserHandle(event.task.key.userId)); 655 656 // Keep track of app-info invocations 657 MetricsLogger.count(this, "overview_app_info", 1); 658 } 659 660 public final void onBusEvent(DeleteTaskDataEvent event) { 661 // Remove any stored data from the loader 662 RecentsTaskLoader loader = Recents.getTaskLoader(); 663 loader.deleteTaskData(event.task, false); 664 665 // Remove the task from activity manager 666 SystemServicesProxy ssp = Recents.getSystemServices(); 667 ssp.removeTask(event.task.key.id); 668 } 669 670 public final void onBusEvent(AllTaskViewsDismissedEvent event) { 671 SystemServicesProxy ssp = Recents.getSystemServices(); 672 if (ssp.hasDockedTask()) { 673 mRecentsView.showEmptyView(event.msgResId); 674 } else { 675 // Just go straight home (no animation necessary because there are no more task views) 676 dismissRecentsToHome(false /* animateTaskViews */); 677 } 678 679 // Keep track of all-deletions 680 MetricsLogger.count(this, "overview_task_all_dismissed", 1); 681 } 682 683 public final void onBusEvent(LaunchTaskSucceededEvent event) { 684 MetricsLogger.histogram(this, "overview_task_launch_index", event.taskIndexFromStackFront); 685 } 686 687 public final void onBusEvent(LaunchTaskFailedEvent event) { 688 // Return to Home 689 dismissRecentsToHome(true /* animateTaskViews */); 690 691 MetricsLogger.count(this, "overview_task_launch_failed", 1); 692 } 693 694 public final void onBusEvent(ScreenPinningRequestEvent event) { 695 MetricsLogger.count(this, "overview_screen_pinned", 1); 696 } 697 698 public final void onBusEvent(DebugFlagsChangedEvent event) { 699 // Just finish recents so that we can reload the flags anew on the next instantiation 700 finish(); 701 } 702 703 public final void onBusEvent(StackViewScrolledEvent event) { 704 // Once the user has scrolled while holding alt-tab, then we should ignore the release of 705 // the key 706 mIgnoreAltTabRelease = true; 707 } 708 709 @Override 710 public boolean onPreDraw() { 711 mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this); 712 // We post to make sure that this information is delivered after this traversals is 713 // finished. 714 mRecentsView.post(new Runnable() { 715 @Override 716 public void run() { 717 Recents.getSystemServices().endProlongedAnimations(); 718 } 719 }); 720 return true; 721 } 722 723 /** 724 * Updates the nav bar scrim. 725 */ 726 private void updateNavBarScrim(boolean animateNavBarScrim, AnimationProps animation) { 727 // Animate the SystemUI scrims into view 728 SystemServicesProxy ssp = Recents.getSystemServices(); 729 int taskCount = mRecentsView.getStack().getTaskCount(); 730 boolean hasNavBarScrim = (taskCount > 0) && !ssp.hasTransposedNavBar(); 731 mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim); 732 if (animateNavBarScrim && animation != null) { 733 mScrimViews.animateNavBarScrimVisibility(true, animation); 734 } 735 } 736} 737