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