RecentsActivity.java revision c28098f69b8ba5d3039ecd0fa154e880f4613843
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.app.TaskStackBuilder; 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.pm.ActivityInfo; 30import android.net.Uri; 31import android.os.Bundle; 32import android.os.SystemClock; 33import android.os.UserHandle; 34import android.provider.Settings; 35import android.view.KeyEvent; 36import android.view.View; 37import android.view.ViewStub; 38import com.android.internal.logging.MetricsLogger; 39import com.android.systemui.R; 40import com.android.systemui.recents.events.EventBus; 41import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent; 42import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent; 43import com.android.systemui.recents.events.activity.HideRecentsEvent; 44import com.android.systemui.recents.events.activity.IterateRecentsEvent; 45import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; 46import com.android.systemui.recents.events.activity.ToggleRecentsEvent; 47import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 48import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; 49import com.android.systemui.recents.events.ui.DismissTaskViewEvent; 50import com.android.systemui.recents.events.ui.ResizeTaskEvent; 51import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; 52import com.android.systemui.recents.events.ui.UserInteractionEvent; 53import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; 54import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; 55import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; 56import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; 57import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; 58import com.android.systemui.recents.misc.Console; 59import com.android.systemui.recents.misc.DozeTrigger; 60import com.android.systemui.recents.misc.ReferenceCountedTrigger; 61import com.android.systemui.recents.misc.SystemServicesProxy; 62import com.android.systemui.recents.model.RecentsPackageMonitor; 63import com.android.systemui.recents.model.RecentsTaskLoadPlan; 64import com.android.systemui.recents.model.RecentsTaskLoader; 65import com.android.systemui.recents.model.Task; 66import com.android.systemui.recents.model.TaskStack; 67import com.android.systemui.recents.views.RecentsView; 68import com.android.systemui.recents.views.SystemBarScrimViews; 69import com.android.systemui.recents.views.ViewAnimation; 70 71import java.util.ArrayList; 72 73/** 74 * The main Recents activity that is started from AlternateRecentsComponent. 75 */ 76public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks { 77 78 private final static String TAG = "RecentsActivity"; 79 private final static boolean DEBUG = false; 80 81 public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1; 82 83 RecentsPackageMonitor mPackageMonitor; 84 long mLastTabKeyEventTime; 85 boolean mFinishedOnStartup; 86 87 // Top level views 88 RecentsView mRecentsView; 89 SystemBarScrimViews mScrimViews; 90 ViewStub mEmptyViewStub; 91 View mEmptyView; 92 93 // Resize task debug 94 RecentsResizeTaskDialog mResizeTaskDebugDialog; 95 96 // Search AppWidget 97 AppWidgetProviderInfo mSearchWidgetInfo; 98 RecentsAppWidgetHost mAppWidgetHost; 99 RecentsAppWidgetHostView mSearchWidgetHostView; 100 101 // Runnables to finish the Recents activity 102 FinishRecentsRunnable mFinishLaunchHomeRunnable; 103 104 // Runnable to be executed after we paused ourselves 105 Runnable mAfterPauseRunnable; 106 107 // The trigger to automatically launch the current task 108 DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() { 109 @Override 110 public void run() { 111 boolean dismissed = dismissRecentsToFocusedTask(false); 112 } 113 }); 114 115 /** 116 * A common Runnable to finish Recents either by calling finish() (with a custom animation) or 117 * launching Home with some ActivityOptions. Generally we always launch home when we exit 118 * Recents rather than just finishing the activity since we don't know what is behind Recents in 119 * the task stack. The only case where we finish() directly is when we are cancelling the full 120 * screen transition from the app. 121 */ 122 class FinishRecentsRunnable implements Runnable { 123 Intent mLaunchIntent; 124 ActivityOptions mLaunchOpts; 125 126 /** 127 * Creates a finish runnable that starts the specified intent, using the given 128 * ActivityOptions. 129 */ 130 public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) { 131 mLaunchIntent = launchIntent; 132 mLaunchOpts = opts; 133 } 134 135 @Override 136 public void run() { 137 try { 138 startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT); 139 } catch (Exception e) { 140 Console.logError(RecentsActivity.this, 141 getString(R.string.recents_launch_error_message, "Home")); 142 } 143 } 144 } 145 146 /** 147 * Broadcast receiver to handle messages from the system 148 */ 149 final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() { 150 @Override 151 public void onReceive(Context context, Intent intent) { 152 String action = intent.getAction(); 153 if (action.equals(Intent.ACTION_SCREEN_OFF)) { 154 // When the screen turns off, dismiss Recents to Home 155 dismissRecentsToHomeIfVisible(false); 156 } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) { 157 // When the search activity changes, update the search widget view 158 SystemServicesProxy ssp = Recents.getSystemServices(); 159 mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(context, mAppWidgetHost); 160 refreshSearchWidgetView(); 161 } 162 } 163 }; 164 165 /** Updates the set of recent tasks */ 166 void updateRecentsTasks() { 167 // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent 168 // reconstructing the task stack 169 RecentsTaskLoader loader = Recents.getTaskLoader(); 170 RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan(); 171 if (plan == null) { 172 plan = loader.createLoadPlan(this); 173 } 174 175 // Start loading tasks according to the load plan 176 RecentsConfiguration config = Recents.getConfiguration(); 177 RecentsActivityLaunchState launchState = config.getLaunchState(); 178 if (!plan.hasTasks()) { 179 loader.preloadTasks(plan, launchState.launchedFromHome); 180 } 181 RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); 182 loadOpts.runningTaskId = launchState.launchedToTaskId; 183 loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; 184 loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; 185 loader.loadTasks(this, plan, loadOpts); 186 187 TaskStack stack = plan.getTaskStack(); 188 launchState.launchedWithNoRecentTasks = !plan.hasTasks(); 189 if (!launchState.launchedWithNoRecentTasks) { 190 mRecentsView.setTaskStack(stack); 191 } 192 193 // Create the home intent runnable 194 Intent homeIntent = new Intent(Intent.ACTION_MAIN, null); 195 homeIntent.addCategory(Intent.CATEGORY_HOME); 196 homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 197 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 198 mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, 199 ActivityOptions.makeCustomAnimation(this, 200 launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter : 201 R.anim.recents_to_launcher_enter, 202 launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit : 203 R.anim.recents_to_launcher_exit)); 204 205 // Mark the task that is the launch target 206 int launchTaskIndexInStack = 0; 207 if (launchState.launchedToTaskId != -1) { 208 ArrayList<Task> tasks = stack.getTasks(); 209 int taskCount = tasks.size(); 210 for (int j = 0; j < taskCount; j++) { 211 Task t = tasks.get(j); 212 if (t.key.id == launchState.launchedToTaskId) { 213 t.isLaunchTarget = true; 214 launchTaskIndexInStack = tasks.size() - j - 1; 215 break; 216 } 217 } 218 } 219 220 // Update the top level view's visibilities 221 if (launchState.launchedWithNoRecentTasks) { 222 if (mEmptyView == null) { 223 mEmptyView = mEmptyViewStub.inflate(); 224 } 225 mEmptyView.setVisibility(View.VISIBLE); 226 if (!Constants.DebugFlags.App.DisableSearchBar) { 227 mRecentsView.setSearchBarVisibility(View.GONE); 228 } 229 } else { 230 if (mEmptyView != null) { 231 mEmptyView.setVisibility(View.GONE); 232 } 233 if (!Constants.DebugFlags.App.DisableSearchBar) { 234 if (mRecentsView.hasValidSearchBar()) { 235 mRecentsView.setSearchBarVisibility(View.VISIBLE); 236 } else { 237 refreshSearchWidgetView(); 238 } 239 } 240 } 241 242 // Animate the SystemUI scrims into view 243 mScrimViews.prepareEnterRecentsAnimation(); 244 245 // Keep track of whether we launched from the nav bar button or via alt-tab 246 if (launchState.launchedWithAltTab) { 247 MetricsLogger.count(this, "overview_trigger_alttab", 1); 248 } else { 249 MetricsLogger.count(this, "overview_trigger_nav_btn", 1); 250 } 251 // Keep track of whether we launched from an app or from home 252 if (launchState.launchedFromAppWithThumbnail) { 253 MetricsLogger.count(this, "overview_source_app", 1); 254 // If from an app, track the stack index of the app in the stack (for affiliated tasks) 255 MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack); 256 } else { 257 MetricsLogger.count(this, "overview_source_home", 1); 258 } 259 // Keep track of the total stack task count 260 int taskCount = stack.getTaskCount(); 261 MetricsLogger.histogram(this, "overview_task_count", taskCount); 262 } 263 264 /** 265 * Dismisses recents if we are already visible and the intent is to toggle the recents view. 266 */ 267 boolean dismissRecentsToFocusedTask(boolean checkFilteredStackState) { 268 SystemServicesProxy ssp = Recents.getSystemServices(); 269 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 270 // If we currently have filtered stacks, then unfilter those first 271 if (checkFilteredStackState && 272 mRecentsView.unfilterFilteredStacks()) return true; 273 // If we have a focused Task, launch that Task now 274 if (mRecentsView.launchFocusedTask()) return true; 275 } 276 return false; 277 } 278 279 /** 280 * Dismisses recents if we are already visible and the intent is to toggle the recents view. 281 */ 282 boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) { 283 RecentsConfiguration config = Recents.getConfiguration(); 284 RecentsActivityLaunchState launchState = config.getLaunchState(); 285 SystemServicesProxy ssp = Recents.getSystemServices(); 286 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 287 // If we currently have filtered stacks, then unfilter those first 288 if (checkFilteredStackState && 289 mRecentsView.unfilterFilteredStacks()) return true; 290 // If we have a focused Task, launch that Task now 291 if (mRecentsView.launchFocusedTask()) return true; 292 // If we launched from Home, then return to Home 293 if (launchState.launchedFromHome) { 294 dismissRecentsToHome(true); 295 return true; 296 } 297 // Otherwise, try and return to the Task that Recents was launched from 298 if (mRecentsView.launchPreviousTask()) return true; 299 // If none of the other cases apply, then just go Home 300 dismissRecentsToHome(true); 301 return true; 302 } 303 return false; 304 } 305 306 /** 307 * Dismisses Recents directly to Home without checking whether it is currently visible. 308 */ 309 void dismissRecentsToHome(boolean animated) { 310 if (animated) { 311 ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, 312 null, mFinishLaunchHomeRunnable, null); 313 mRecentsView.startExitToHomeAnimation( 314 new ViewAnimation.TaskViewExitContext(exitTrigger)); 315 } else { 316 mFinishLaunchHomeRunnable.run(); 317 } 318 } 319 320 /** Dismisses Recents directly to Home without transition animation. */ 321 void dismissRecentsToHomeWithoutTransitionAnimation() { 322 finish(); 323 overridePendingTransition(0, 0); 324 } 325 326 /** Dismisses Recents directly to Home if we currently aren't transitioning. */ 327 boolean dismissRecentsToHomeIfVisible(boolean animated) { 328 SystemServicesProxy ssp = Recents.getSystemServices(); 329 if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { 330 // Return to Home 331 dismissRecentsToHome(animated); 332 return true; 333 } 334 return false; 335 } 336 337 /** Called with the activity is first created. */ 338 @Override 339 public void onCreate(Bundle savedInstanceState) { 340 super.onCreate(savedInstanceState); 341 mFinishedOnStartup = false; 342 343 // In the case that the activity starts up before the Recents component has initialized 344 // (usually when debugging/pushing the SysUI apk), just finish this activity. 345 SystemServicesProxy ssp = Recents.getSystemServices(); 346 if (ssp == null) { 347 mFinishedOnStartup = true; 348 finish(); 349 return; 350 } 351 352 // Register this activity with the event bus 353 EventBus.getDefault().register(this, EVENT_BUS_PRIORITY); 354 355 // Initialize the widget host (the host id is static and does not change) 356 if (!Constants.DebugFlags.App.DisableSearchBar) { 357 mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId); 358 } 359 mPackageMonitor = new RecentsPackageMonitor(); 360 mPackageMonitor.register(this); 361 362 // Set the Recents layout 363 setContentView(R.layout.recents); 364 mRecentsView = (RecentsView) findViewById(R.id.recents_view); 365 mRecentsView.setCallbacks(this); 366 mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | 367 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 368 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 369 mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub); 370 mScrimViews = new SystemBarScrimViews(this); 371 372 // Bind the search app widget when we first start up 373 if (!Constants.DebugFlags.App.DisableSearchBar) { 374 mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost); 375 } 376 377 // Register the broadcast receiver to handle messages when the screen is turned off 378 IntentFilter filter = new IntentFilter(); 379 filter.addAction(Intent.ACTION_SCREEN_OFF); 380 if (!Constants.DebugFlags.App.DisableSearchBar) { 381 filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); 382 } 383 registerReceiver(mSystemBroadcastReceiver, filter); 384 } 385 386 @Override 387 protected void onNewIntent(Intent intent) { 388 super.onNewIntent(intent); 389 setIntent(intent); 390 } 391 392 @Override 393 protected void onStart() { 394 super.onStart(); 395 396 // Update the recent tasks 397 updateRecentsTasks(); 398 399 // If this is a new instance from a configuration change, then we have to manually trigger 400 // the enter animation state, or if recents was relaunched by AM, without going through 401 // the normal mechanisms 402 RecentsConfiguration config = Recents.getConfiguration(); 403 RecentsActivityLaunchState launchState = config.getLaunchState(); 404 boolean wasLaunchedByAm = !launchState.launchedFromHome && 405 !launchState.launchedFromAppWithThumbnail; 406 if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) { 407 EventBus.getDefault().send(new EnterRecentsWindowAnimationStartedEvent()); 408 } 409 410 if (!launchState.launchedHasConfigurationChanged) { 411 mRecentsView.disableLayersForOneFrame(); 412 } 413 414 // Notify that recents is now visible 415 SystemServicesProxy ssp = Recents.getSystemServices(); 416 EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true)); 417 418 MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY); 419 } 420 421 @Override 422 protected void onResume() { 423 super.onResume(); 424 425 final RecentsActivityLaunchState state = Recents.getConfiguration().getLaunchState(); 426 if (state.startHidden) { 427 state.startHidden = false; 428 mRecentsView.setVisibility(View.INVISIBLE); 429 } 430 } 431 432 @Override 433 protected void onPause() { 434 super.onPause(); 435 if (mAfterPauseRunnable != null) { 436 mRecentsView.post(mAfterPauseRunnable); 437 mAfterPauseRunnable = null; 438 } 439 440 if (Constants.DebugFlags.App.EnableFastToggleRecents) { 441 // Stop the fast-toggle dozer 442 mIterateTrigger.stopDozing(); 443 } 444 } 445 446 @Override 447 protected void onStop() { 448 super.onStop(); 449 450 // Notify that recents is now hidden 451 SystemServicesProxy ssp = Recents.getSystemServices(); 452 EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false)); 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.launchedFromHome = false; 460 launchState.launchedFromSearchHome = false; 461 launchState.launchedFromAppWithThumbnail = false; 462 launchState.launchedToTaskId = -1; 463 launchState.launchedWithAltTab = false; 464 launchState.launchedHasConfigurationChanged = false; 465 466 MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY); 467 } 468 469 @Override 470 protected void onDestroy() { 471 super.onDestroy(); 472 473 // In the case that the activity finished on startup, just skip the unregistration below 474 if (mFinishedOnStartup) { 475 return; 476 } 477 478 // Unregister the system broadcast receivers 479 unregisterReceiver(mSystemBroadcastReceiver); 480 481 // Unregister any broadcast receivers for the task loader 482 mPackageMonitor.unregister(); 483 484 // Stop listening for widget package changes if there was one bound 485 if (!Constants.DebugFlags.App.DisableSearchBar) { 486 mAppWidgetHost.stopListening(); 487 } 488 489 EventBus.getDefault().unregister(this); 490 } 491 492 @Override 493 public void onAttachedToWindow() { 494 super.onAttachedToWindow(); 495 EventBus.getDefault().register(mScrimViews, EVENT_BUS_PRIORITY); 496 } 497 498 @Override 499 public void onDetachedFromWindow() { 500 super.onDetachedFromWindow(); 501 EventBus.getDefault().unregister(mScrimViews); 502 } 503 504 @Override 505 public void onTrimMemory(int level) { 506 RecentsTaskLoader loader = Recents.getTaskLoader(); 507 if (loader != null) { 508 loader.onTrimMemory(level); 509 } 510 } 511 512 @Override 513 public boolean onKeyDown(int keyCode, KeyEvent event) { 514 switch (keyCode) { 515 case KeyEvent.KEYCODE_TAB: { 516 int altTabKeyDelay = getResources().getInteger(R.integer.recents_alt_tab_key_delay); 517 boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() - 518 mLastTabKeyEventTime) > altTabKeyDelay; 519 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) { 520 // As we iterate to the next/previous task, cancel any current/lagging window 521 // transition animations 522 RecentsConfiguration config = Recents.getConfiguration(); 523 RecentsActivityLaunchState launchState = config.getLaunchState(); 524 if (launchState.launchedToTaskId != -1) { 525 SystemServicesProxy ssp = Recents.getSystemServices(); 526 ssp.cancelWindowTransition(launchState.launchedToTaskId); 527 } 528 529 // Focus the next task in the stack 530 final boolean backward = event.isShiftPressed(); 531 if (backward) { 532 EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); 533 } else { 534 EventBus.getDefault().send(new FocusNextTaskViewEvent()); 535 } 536 mLastTabKeyEventTime = SystemClock.elapsedRealtime(); 537 } 538 return true; 539 } 540 case KeyEvent.KEYCODE_DPAD_UP: { 541 EventBus.getDefault().send(new FocusNextTaskViewEvent()); 542 return true; 543 } 544 case KeyEvent.KEYCODE_DPAD_DOWN: { 545 EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); 546 return true; 547 } 548 case KeyEvent.KEYCODE_DEL: 549 case KeyEvent.KEYCODE_FORWARD_DEL: { 550 EventBus.getDefault().send(new DismissFocusedTaskViewEvent()); 551 552 // Keep track of deletions by keyboard 553 MetricsLogger.histogram(this, "overview_task_dismissed_source", 554 Constants.Metrics.DismissSourceKeyboard); 555 return true; 556 } 557 default: 558 break; 559 } 560 return super.onKeyDown(keyCode, event); 561 } 562 563 @Override 564 public void onUserInteraction() { 565 EventBus.getDefault().send(new UserInteractionEvent()); 566 } 567 568 @Override 569 public void onBackPressed() { 570 // Dismiss Recents to the focused Task or Home 571 dismissRecentsToFocusedTaskOrHome(true); 572 } 573 574 /**** RecentsResizeTaskDialog ****/ 575 576 private RecentsResizeTaskDialog getResizeTaskDebugDialog() { 577 if (mResizeTaskDebugDialog == null) { 578 mResizeTaskDebugDialog = new RecentsResizeTaskDialog(getFragmentManager(), this); 579 } 580 return mResizeTaskDebugDialog; 581 } 582 583 /**** RecentsView.RecentsViewCallbacks Implementation ****/ 584 585 @Override 586 public void onTaskViewClicked() { 587 } 588 589 @Override 590 public void onTaskLaunchFailed() { 591 // Return to Home 592 dismissRecentsToHome(true); 593 } 594 595 @Override 596 public void onAllTaskViewsDismissed() { 597 mFinishLaunchHomeRunnable.run(); 598 } 599 600 @Override 601 public void runAfterPause(Runnable r) { 602 mAfterPauseRunnable = r; 603 } 604 605 /**** EventBus events ****/ 606 607 public final void onBusEvent(ToggleRecentsEvent event) { 608 dismissRecentsToFocusedTaskOrHome(true /* checkFilteredStackState */); 609 } 610 611 public final void onBusEvent(IterateRecentsEvent event) { 612 // Focus the next task 613 EventBus.getDefault().send(new FocusNextTaskViewEvent()); 614 mIterateTrigger.poke(); 615 } 616 617 public final void onBusEvent(UserInteractionEvent event) { 618 mIterateTrigger.stopDozing(); 619 } 620 621 public final void onBusEvent(HideRecentsEvent event) { 622 if (event.triggeredFromAltTab) { 623 // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app 624 dismissRecentsToFocusedTaskOrHome(false /* checkFilteredStackState */); 625 } else if (event.triggeredFromHomeKey) { 626 // Otherwise, dismiss Recents to Home 627 dismissRecentsToHome(true /* checkFilteredStackState */); 628 } else { 629 // Do nothing 630 } 631 } 632 633 public final void onBusEvent(EnterRecentsWindowAnimationStartedEvent event) { 634 // Try and start the enter animation (or restart it on configuration changed) 635 ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); 636 ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t); 637 ctx.postAnimationTrigger.increment(); 638 if (mSearchWidgetInfo != null) { 639 if (!Constants.DebugFlags.App.DisableSearchBar) { 640 ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { 641 @Override 642 public void run() { 643 // Start listening for widget package changes if there is one bound 644 if (mAppWidgetHost != null) { 645 mAppWidgetHost.startListening(); 646 } 647 } 648 }); 649 } 650 } 651 ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { 652 @Override 653 public void run() { 654 // If we are not launching with alt-tab and fast-toggle is enabled, then start 655 // the dozer now 656 RecentsConfiguration config = Recents.getConfiguration(); 657 RecentsActivityLaunchState launchState = config.getLaunchState(); 658 if (Constants.DebugFlags.App.EnableFastToggleRecents && 659 !launchState.launchedWithAltTab) { 660 mIterateTrigger.startDozing(); 661 } 662 } 663 }); 664 mRecentsView.startEnterRecentsAnimation(ctx); 665 ctx.postAnimationTrigger.decrement(); 666 } 667 668 public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) { 669 mRecentsView.setVisibility(View.VISIBLE); 670 } 671 672 public final void onBusEvent(AppWidgetProviderChangedEvent event) { 673 refreshSearchWidgetView(); 674 } 675 676 public final void onBusEvent(ShowApplicationInfoEvent event) { 677 // Create a new task stack with the application info details activity 678 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 679 Uri.fromParts("package", event.task.key.getComponent().getPackageName(), null)); 680 intent.setComponent(intent.resolveActivity(getPackageManager())); 681 TaskStackBuilder.create(this) 682 .addNextIntentWithParentStack(intent).startActivities(null, 683 new UserHandle(event.task.key.userId)); 684 685 // Keep track of app-info invocations 686 MetricsLogger.count(this, "overview_app_info", 1); 687 } 688 689 public final void onBusEvent(DismissTaskViewEvent event) { 690 // Remove any stored data from the loader 691 RecentsTaskLoader loader = Recents.getTaskLoader(); 692 loader.deleteTaskData(event.task, false); 693 694 // Remove the task from activity manager 695 SystemServicesProxy ssp = Recents.getSystemServices(); 696 ssp.removeTask(event.task.key.id); 697 } 698 699 public final void onBusEvent(ResizeTaskEvent event) { 700 getResizeTaskDebugDialog().showResizeTaskDialog(event.task, mRecentsView); 701 } 702 703 public final void onBusEvent(DragStartEvent event) { 704 // Lock the orientation while dragging 705 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); 706 707 // TODO: docking requires custom accessibility actions 708 } 709 710 public final void onBusEvent(DragEndEvent event) { 711 // Unlock the orientation when dragging completes 712 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_BEHIND); 713 } 714 715 public final void onBusEvent(ScreenPinningRequestEvent event) { 716 MetricsLogger.count(this, "overview_screen_pinned", 1); 717 } 718 719 private void refreshSearchWidgetView() { 720 if (mSearchWidgetInfo != null) { 721 SystemServicesProxy ssp = Recents.getSystemServices(); 722 int searchWidgetId = ssp.getSearchAppWidgetId(this); 723 mSearchWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView( 724 this, searchWidgetId, mSearchWidgetInfo); 725 Bundle opts = new Bundle(); 726 opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 727 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); 728 mSearchWidgetHostView.updateAppWidgetOptions(opts); 729 // Set the padding to 0 for this search widget 730 mSearchWidgetHostView.setPadding(0, 0, 0, 0); 731 mRecentsView.setSearchBar(mSearchWidgetHostView); 732 } else { 733 mRecentsView.setSearchBar(null); 734 } 735 } 736} 737