RecentsActivity.java revision 969f586533096999f10f5587f901949791154fa2
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.appwidget.AppWidgetHost; 21import android.appwidget.AppWidgetHostView; 22import android.appwidget.AppWidgetManager; 23import android.appwidget.AppWidgetProviderInfo; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.os.Bundle; 29import android.util.Pair; 30import android.view.Gravity; 31import android.view.KeyEvent; 32import android.view.LayoutInflater; 33import android.view.View; 34import android.view.ViewGroup; 35import android.widget.FrameLayout; 36import com.android.systemui.R; 37import com.android.systemui.recents.model.SpaceNode; 38import com.android.systemui.recents.model.TaskStack; 39import com.android.systemui.recents.views.FullScreenTransitionView; 40import com.android.systemui.recents.views.RecentsView; 41import com.android.systemui.recents.views.ViewAnimation; 42 43import java.lang.reflect.InvocationTargetException; 44import java.lang.reflect.Method; 45import java.util.ArrayList; 46 47/** Our special app widget host */ 48class RecentsAppWidgetHost extends AppWidgetHost { 49 /* Callbacks to notify when an app package changes */ 50 interface RecentsAppWidgetHostCallbacks { 51 public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo); 52 } 53 54 RecentsAppWidgetHostCallbacks mCb; 55 56 public RecentsAppWidgetHost(Context context, int hostId, RecentsAppWidgetHostCallbacks cb) { 57 super(context, hostId); 58 mCb = cb; 59 } 60 61 @Override 62 protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) { 63 mCb.onProviderChanged(appWidgetId, appWidget); 64 } 65} 66 67/* Activity */ 68public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks, 69 RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks, 70 FullScreenTransitionView.FullScreenTransitionViewCallbacks { 71 72 FrameLayout mContainerView; 73 RecentsView mRecentsView; 74 View mEmptyView; 75 View mNavBarScrimView; 76 FullScreenTransitionView mFullScreenshotView; 77 78 RecentsConfiguration mConfig; 79 80 AppWidgetHost mAppWidgetHost; 81 AppWidgetProviderInfo mSearchAppWidgetInfo; 82 AppWidgetHostView mSearchAppWidgetHostView; 83 84 boolean mVisible; 85 boolean mTaskLaunched; 86 87 private static Method sPropertyMethod; 88 static { 89 try { 90 Class<?> c = Class.forName("android.view.GLES20Canvas"); 91 sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class); 92 if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true); 93 } catch (ClassNotFoundException e) { 94 e.printStackTrace(); 95 } catch (NoSuchMethodException e) { 96 e.printStackTrace(); 97 } 98 } 99 100 // Broadcast receiver to handle messages from our RecentsService 101 BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() { 102 @Override 103 public void onReceive(Context context, Intent intent) { 104 String action = intent.getAction(); 105 if (Console.Enabled) { 106 Console.log(Constants.Log.App.SystemUIHandshake, 107 "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed); 108 } 109 if (action.equals(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY)) { 110 if (intent.getBooleanExtra(RecentsService.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) { 111 // Dismiss recents, launching the focused task 112 dismissRecentsIfVisible(); 113 } else { 114 // If we are mid-animation into Recents, then reverse it and finish 115 if (mFullScreenshotView == null || 116 !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) { 117 // Otherwise, just finish the activity without launching any other activities 118 ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(context, 119 null, mFinishRunnable, null); 120 mRecentsView.startExitToHomeAnimation( 121 new ViewAnimation.TaskViewExitContext(exitTrigger)); 122 } 123 } 124 } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) { 125 // Try and unfilter and filtered stacks 126 if (!mRecentsView.unfilterFilteredStacks()) { 127 // If there are no filtered stacks, dismiss recents and launch the first task 128 dismissRecentsIfVisible(); 129 } 130 } else if (action.equals(RecentsService.ACTION_START_ENTER_ANIMATION)) { 131 // Try and start the enter animation (or restart it on configuration changed) 132 mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenshotView)); 133 // Call our callback 134 onEnterAnimationTriggered(); 135 } 136 } 137 }; 138 139 // Broadcast receiver to handle messages from the system 140 BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 141 @Override 142 public void onReceive(Context context, Intent intent) { 143 // Mark recents as no longer visible 144 AlternateRecentsComponent.notifyVisibilityChanged(false); 145 // Finish without an animations 146 finish(); 147 } 148 }; 149 150 // A runnable to finish the Recents activity 151 Runnable mFinishRunnable = new Runnable() { 152 @Override 153 public void run() { 154 // Mark recents as no longer visible 155 AlternateRecentsComponent.notifyVisibilityChanged(false); 156 // Finish with an animations 157 finish(); 158 overridePendingTransition(R.anim.recents_to_launcher_enter, 159 R.anim.recents_to_launcher_exit); 160 } 161 }; 162 163 /** Updates the set of recent tasks */ 164 void updateRecentsTasks(Intent launchIntent) { 165 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 166 SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount); 167 ArrayList<TaskStack> stacks = root.getStacks(); 168 if (!stacks.isEmpty()) { 169 mRecentsView.setBSP(root); 170 } 171 172 // Update the configuration based on the launch intent 173 mConfig.launchedFromHome = launchIntent.getBooleanExtra( 174 AlternateRecentsComponent.EXTRA_FROM_HOME, false); 175 mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra( 176 AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false); 177 mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra( 178 AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false); 179 mConfig.launchedWithAltTab = launchIntent.getBooleanExtra( 180 AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false); 181 mConfig.launchedWithNoRecentTasks = !root.hasTasks(); 182 183 if (mConfig.shouldAnimateNavBarScrim()) { 184 // Hide the scrim if we animate into Recents with window transitions 185 mNavBarScrimView.setVisibility(View.INVISIBLE); 186 } else { 187 // Show the scrim if we animate into Recents without window transitions 188 mNavBarScrimView.setVisibility(View.VISIBLE); 189 } 190 191 // Add the default no-recents layout 192 if (mConfig.launchedWithNoRecentTasks) { 193 mEmptyView.setVisibility(View.VISIBLE); 194 mEmptyView.setBackgroundColor(0x80000000); 195 } else { 196 mEmptyView.setVisibility(View.GONE); 197 } 198 } 199 200 /** Attempts to allocate and bind the search bar app widget */ 201 void bindSearchBarAppWidget() { 202 if (Constants.DebugFlags.App.EnableSearchLayout) { 203 SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); 204 205 // Reset the host view and widget info 206 mSearchAppWidgetHostView = null; 207 mSearchAppWidgetInfo = null; 208 209 // Try and load the app widget id from the settings 210 int appWidgetId = mConfig.searchBarAppWidgetId; 211 if (appWidgetId >= 0) { 212 mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId); 213 if (mSearchAppWidgetInfo == null) { 214 // If there is no actual widget associated with that id, then delete it and 215 // prepare to bind another app widget in its place 216 ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId); 217 appWidgetId = -1; 218 } 219 if (Console.Enabled) { 220 Console.log(Constants.Log.App.SystemUIHandshake, 221 "[RecentsActivity|onCreate|settings|appWidgetId]", 222 "Id: " + appWidgetId, 223 Console.AnsiBlue); 224 } 225 } 226 227 // If there is no id, then bind a new search app widget 228 if (appWidgetId < 0) { 229 Pair<Integer, AppWidgetProviderInfo> widgetInfo = 230 ssp.bindSearchAppWidget(mAppWidgetHost); 231 if (widgetInfo != null) { 232 if (Console.Enabled) { 233 Console.log(Constants.Log.App.SystemUIHandshake, 234 "[RecentsActivity|onCreate|searchWidget]", 235 "Id: " + widgetInfo.first + " Info: " + widgetInfo.second, 236 Console.AnsiBlue); 237 } 238 239 // Save the app widget id into the settings 240 mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first); 241 mSearchAppWidgetInfo = widgetInfo.second; 242 } 243 } 244 } 245 } 246 247 /** Creates the search bar app widget view */ 248 void addSearchBarAppWidgetView() { 249 if (Constants.DebugFlags.App.EnableSearchLayout) { 250 int appWidgetId = mConfig.searchBarAppWidgetId; 251 if (appWidgetId >= 0) { 252 if (Console.Enabled) { 253 Console.log(Constants.Log.App.SystemUIHandshake, 254 "[RecentsActivity|onCreate|addSearchAppWidgetView]", 255 "Id: " + appWidgetId, 256 Console.AnsiBlue); 257 } 258 mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId, 259 mSearchAppWidgetInfo); 260 Bundle opts = new Bundle(); 261 opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 262 AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS); 263 mSearchAppWidgetHostView.updateAppWidgetOptions(opts); 264 // Set the padding to 0 for this search widget 265 mSearchAppWidgetHostView.setPadding(0, 0, 0, 0); 266 mRecentsView.setSearchBar(mSearchAppWidgetHostView); 267 } else { 268 mRecentsView.setSearchBar(null); 269 } 270 } 271 } 272 273 /** Dismisses recents if we are already visible and the intent is to toggle the recents view */ 274 boolean dismissRecentsIfVisible() { 275 if (mVisible) { 276 // If we are mid-animation into Recents, then reverse it and finish 277 if (mFullScreenshotView == null || 278 !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) { 279 // If we have a focused task, then launch that task 280 if (!mRecentsView.launchFocusedTask()) { 281 // If there are any tasks, then launch the first task 282 if (!mRecentsView.launchFirstTask()) { 283 // We really shouldn't hit this, but if we do, just animate out (aka. finish) 284 ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, 285 null, mFinishRunnable, null); 286 mRecentsView.startExitToHomeAnimation( 287 new ViewAnimation.TaskViewExitContext(exitTrigger)); 288 } 289 } 290 } 291 return true; 292 } 293 return false; 294 } 295 296 /** Called with the activity is first created. */ 297 @Override 298 public void onCreate(Bundle savedInstanceState) { 299 super.onCreate(savedInstanceState); 300 if (Console.Enabled) { 301 Console.logDivider(Constants.Log.App.SystemUIHandshake); 302 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]", 303 getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed); 304 Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, 305 Constants.Log.App.TimeRecentsStartupKey, "onCreate"); 306 } 307 308 // Initialize the loader and the configuration 309 RecentsTaskLoader.initialize(this); 310 mConfig = RecentsConfiguration.reinitialize(this); 311 312 // Initialize the widget host (the host id is static and does not change) 313 mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId, this); 314 315 // Create the view hierarchy 316 mRecentsView = new RecentsView(this); 317 mRecentsView.setCallbacks(this); 318 mRecentsView.setLayoutParams(new FrameLayout.LayoutParams( 319 FrameLayout.LayoutParams.MATCH_PARENT, 320 FrameLayout.LayoutParams.MATCH_PARENT)); 321 mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | 322 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 323 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 324 325 // Create the empty view 326 LayoutInflater inflater = LayoutInflater.from(this); 327 mEmptyView = inflater.inflate(R.layout.recents_empty, mContainerView, false); 328 mNavBarScrimView = inflater.inflate(R.layout.recents_nav_bar_scrim, mContainerView, false); 329 mNavBarScrimView.setLayoutParams(new FrameLayout.LayoutParams( 330 ViewGroup.LayoutParams.MATCH_PARENT, 331 ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); 332 if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { 333 mFullScreenshotView = new FullScreenTransitionView(this, this); 334 mFullScreenshotView.setLayoutParams(new FrameLayout.LayoutParams( 335 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 336 } 337 338 mContainerView = new FrameLayout(this); 339 mContainerView.addView(mRecentsView); 340 mContainerView.addView(mEmptyView); 341 if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { 342 mContainerView.addView(mFullScreenshotView); 343 } 344 mContainerView.addView(mNavBarScrimView); 345 setContentView(mContainerView); 346 347 // Update the recent tasks 348 updateRecentsTasks(getIntent()); 349 350 // Prepare the screenshot transition if necessary 351 if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { 352 mFullScreenshotView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot()); 353 } 354 355 // Bind the search app widget when we first start up 356 bindSearchBarAppWidget(); 357 // Add the search bar layout 358 addSearchBarAppWidgetView(); 359 360 // Update if we are getting a configuration change 361 if (savedInstanceState != null) { 362 onConfigurationChange(); 363 } 364 365 // XXX: Update the shadows 366 try { 367 sPropertyMethod.invoke(null, "ambientShadowStrength", String.valueOf(35f)); 368 sPropertyMethod.invoke(null, "ambientRatio", String.valueOf(0.5f)); 369 } catch (IllegalAccessException e) { 370 e.printStackTrace(); 371 } catch (InvocationTargetException e) { 372 e.printStackTrace(); 373 } 374 } 375 376 void onConfigurationChange() { 377 // Try and start the enter animation (or restart it on configuration changed) 378 mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenshotView)); 379 // Call our callback 380 onEnterAnimationTriggered(); 381 } 382 383 @Override 384 protected void onNewIntent(Intent intent) { 385 super.onNewIntent(intent); 386 // Reset the task launched flag if we encounter an onNewIntent() before onStop() 387 mTaskLaunched = false; 388 389 if (Console.Enabled) { 390 Console.logDivider(Constants.Log.App.SystemUIHandshake); 391 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]", 392 intent.getAction() + " visible: " + mVisible, Console.AnsiRed); 393 Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, 394 Constants.Log.App.TimeRecentsStartupKey, "onNewIntent"); 395 } 396 397 // Initialize the loader and the configuration 398 RecentsTaskLoader.initialize(this); 399 mConfig = RecentsConfiguration.reinitialize(this); 400 401 // Update the recent tasks 402 updateRecentsTasks(intent); 403 404 // Prepare the screenshot transition if necessary 405 if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { 406 mFullScreenshotView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot()); 407 } 408 409 // Don't attempt to rebind the search bar widget, but just add the search bar layout 410 addSearchBarAppWidgetView(); 411 } 412 413 @Override 414 protected void onStart() { 415 if (Console.Enabled) { 416 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "", 417 Console.AnsiRed); 418 } 419 super.onStart(); 420 421 // Start listening for widget package changes if there is one bound 422 if (mConfig.searchBarAppWidgetId >= 0) { 423 mAppWidgetHost.startListening(); 424 } 425 426 mVisible = true; 427 } 428 429 @Override 430 protected void onResume() { 431 if (Console.Enabled) { 432 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "", 433 Console.AnsiRed); 434 } 435 super.onResume(); 436 } 437 438 @Override 439 public void onAttachedToWindow() { 440 if (Console.Enabled) { 441 Console.log(Constants.Log.App.SystemUIHandshake, 442 "[RecentsActivity|onAttachedToWindow]", "", 443 Console.AnsiRed); 444 } 445 super.onAttachedToWindow(); 446 447 // Register the broadcast receiver to handle messages from our service 448 IntentFilter filter = new IntentFilter(); 449 filter.addAction(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY); 450 filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY); 451 filter.addAction(RecentsService.ACTION_START_ENTER_ANIMATION); 452 registerReceiver(mServiceBroadcastReceiver, filter); 453 454 // Register the broadcast receiver to handle messages when the screen is turned off 455 filter = new IntentFilter(); 456 filter.addAction(Intent.ACTION_SCREEN_OFF); 457 registerReceiver(mScreenOffReceiver, filter); 458 459 // Register any broadcast receivers for the task loader 460 RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView); 461 } 462 463 @Override 464 public void onDetachedFromWindow() { 465 if (Console.Enabled) { 466 Console.log(Constants.Log.App.SystemUIHandshake, 467 "[RecentsActivity|onDetachedFromWindow]", "", 468 Console.AnsiRed); 469 } 470 super.onDetachedFromWindow(); 471 472 // Unregister any broadcast receivers we have registered 473 unregisterReceiver(mServiceBroadcastReceiver); 474 unregisterReceiver(mScreenOffReceiver); 475 RecentsTaskLoader.getInstance().unregisterReceivers(); 476 } 477 478 @Override 479 protected void onPause() { 480 if (Console.Enabled) { 481 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "", 482 Console.AnsiRed); 483 } 484 super.onPause(); 485 } 486 487 @Override 488 protected void onStop() { 489 if (Console.Enabled) { 490 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "", 491 Console.AnsiRed); 492 } 493 super.onStop(); 494 495 // Stop listening for widget package changes if there was one bound 496 if (mConfig.searchBarAppWidgetId >= 0) { 497 mAppWidgetHost.stopListening(); 498 } 499 500 mVisible = false; 501 mTaskLaunched = false; 502 } 503 504 @Override 505 protected void onDestroy() { 506 if (Console.Enabled) { 507 Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "", 508 Console.AnsiRed); 509 } 510 super.onDestroy(); 511 } 512 513 @Override 514 public void onTrimMemory(int level) { 515 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 516 if (loader != null) { 517 loader.onTrimMemory(level); 518 } 519 } 520 521 @Override 522 public boolean onKeyDown(int keyCode, KeyEvent event) { 523 if (keyCode == KeyEvent.KEYCODE_TAB) { 524 // Focus the next task in the stack 525 final boolean backward = event.isShiftPressed(); 526 mRecentsView.focusNextTask(!backward); 527 return true; 528 } 529 530 return super.onKeyDown(keyCode, event); 531 } 532 533 @Override 534 public void onUserInteraction() { 535 mRecentsView.onUserInteraction(); 536 } 537 538 @Override 539 public void onBackPressed() { 540 // If we are mid-animation into Recents, then reverse it and finish 541 if (mFullScreenshotView == null || 542 !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) { 543 // If we are currently filtering in any stacks, unfilter them first 544 if (!mRecentsView.unfilterFilteredStacks()) { 545 if (mConfig.launchedFromHome) { 546 // Just start the animation out of recents 547 ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, 548 null, mFinishRunnable, null); 549 mRecentsView.startExitToHomeAnimation( 550 new ViewAnimation.TaskViewExitContext(exitTrigger)); 551 } else { 552 // Otherwise, try and launch the first task 553 if (!mRecentsView.launchFirstTask()) { 554 // If there are no tasks, then just finish recents 555 ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, 556 null, mFinishRunnable, null); 557 mRecentsView.startExitToHomeAnimation( 558 new ViewAnimation.TaskViewExitContext(exitTrigger)); 559 } 560 } 561 } 562 } 563 } 564 565 public void onEnterAnimationTriggered() { 566 // Fade in the scrim 567 if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) { 568 mNavBarScrimView.setVisibility(View.VISIBLE); 569 mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight()); 570 mNavBarScrimView.animate() 571 .translationY(0) 572 .setStartDelay(mConfig.taskBarEnterAnimDelay) 573 .setDuration(mConfig.navBarScrimEnterDuration) 574 .setInterpolator(mConfig.quintOutInterpolator) 575 .start(); 576 } 577 } 578 579 @Override 580 public void onExitAnimationTriggered() { 581 // Fade out the scrim 582 if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) { 583 mNavBarScrimView.animate() 584 .translationY(mNavBarScrimView.getMeasuredHeight()) 585 .setStartDelay(0) 586 .setDuration(mConfig.taskBarExitAnimDuration) 587 .setInterpolator(mConfig.fastOutSlowInInterpolator) 588 .start(); 589 } 590 } 591 592 @Override 593 public void onEnterAnimationComplete(boolean canceled) { 594 if (!canceled) { 595 // Reset the full screenshot transition view 596 if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { 597 mFullScreenshotView.reset(); 598 } 599 600 // XXX: We should clean up the screenshot in this case as well, but it needs to happen 601 // after to animate up 602 } 603 // Recycle the full screen screenshot 604 AlternateRecentsComponent.consumeLastScreenshot(); 605 } 606 607 @Override 608 public void onTaskLaunching(boolean isTaskInStackBounds) { 609 mTaskLaunched = true; 610 611 // Fade out the scrim 612 if (!isTaskInStackBounds && mConfig.hasNavBarScrim()) { 613 onExitAnimationTriggered(); 614 } 615 616 // Mark recents as no longer visible 617 AlternateRecentsComponent.notifyVisibilityChanged(false); 618 } 619 620 @Override 621 public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) { 622 SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); 623 if (appWidgetId > -1 && appWidgetId == mConfig.searchBarAppWidgetId) { 624 // The search provider may have changed, so just delete the old widget and bind it again 625 ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId); 626 mConfig.updateSearchBarAppWidgetId(this, -1); 627 // Load the widget again 628 bindSearchBarAppWidget(); 629 addSearchBarAppWidgetView(); 630 } 631 } 632} 633