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