RecentsView.java revision 250608a5cd08862f4752a924d51710805850db8a
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.views; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.graphics.Canvas; 22import android.graphics.Rect; 23import android.graphics.drawable.Drawable; 24import android.os.Handler; 25import android.util.ArraySet; 26import android.util.AttributeSet; 27import android.view.LayoutInflater; 28import android.view.MotionEvent; 29import android.view.View; 30import android.view.WindowInsets; 31import android.view.animation.AnimationUtils; 32import android.view.animation.Interpolator; 33import android.widget.FrameLayout; 34import com.android.systemui.R; 35import com.android.systemui.recents.Recents; 36import com.android.systemui.recents.RecentsActivity; 37import com.android.systemui.recents.RecentsActivityLaunchState; 38import com.android.systemui.recents.RecentsAppWidgetHostView; 39import com.android.systemui.recents.RecentsConfiguration; 40import com.android.systemui.recents.RecentsDebugFlags; 41import com.android.systemui.recents.events.EventBus; 42import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; 43import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent; 44import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; 45import com.android.systemui.recents.events.activity.HideHistoryButtonEvent; 46import com.android.systemui.recents.events.activity.HideHistoryEvent; 47import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent; 48import com.android.systemui.recents.events.activity.ShowHistoryEvent; 49import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 50import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; 51import com.android.systemui.recents.events.ui.DraggingInRecentsEvent; 52import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; 53import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; 54import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; 55import com.android.systemui.recents.misc.SystemServicesProxy; 56import com.android.systemui.recents.model.Task; 57import com.android.systemui.recents.model.TaskStack; 58 59import java.util.ArrayList; 60import java.util.List; 61 62import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 63 64/** 65 * This view is the the top level layout that contains TaskStacks (which are laid out according 66 * to their SpaceNode bounds. 67 */ 68public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks { 69 70 private static final String TAG = "RecentsView"; 71 private static final boolean DEBUG = false; 72 73 Handler mHandler; 74 75 TaskStack mStack; 76 TaskStackView mTaskStackView; 77 RecentsAppWidgetHostView mSearchBar; 78 View mHistoryButton; 79 boolean mAwaitingFirstLayout = true; 80 boolean mLastTaskLaunchedWasFreeform; 81 82 RecentsTransitionHelper mTransitionHelper; 83 RecentsViewTouchHandler mTouchHandler; 84 DragView mDragView; 85 TaskStack.DockState[] mVisibleDockStates = { 86 TaskStack.DockState.LEFT, 87 TaskStack.DockState.TOP, 88 TaskStack.DockState.RIGHT, 89 TaskStack.DockState.BOTTOM, 90 }; 91 92 private Interpolator mFastOutSlowInInterpolator; 93 private Interpolator mFastOutLinearInInterpolator; 94 private int mHistoryTransitionDuration; 95 96 Rect mSystemInsets = new Rect(); 97 98 public RecentsView(Context context) { 99 super(context); 100 } 101 102 public RecentsView(Context context, AttributeSet attrs) { 103 this(context, attrs, 0); 104 } 105 106 public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) { 107 this(context, attrs, defStyleAttr, 0); 108 } 109 110 public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 111 super(context, attrs, defStyleAttr, defStyleRes); 112 Resources res = context.getResources(); 113 setWillNotDraw(false); 114 mHandler = new Handler(); 115 mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler); 116 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 117 com.android.internal.R.interpolator.fast_out_slow_in); 118 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, 119 com.android.internal.R.interpolator.fast_out_linear_in); 120 mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration); 121 mTouchHandler = new RecentsViewTouchHandler(this); 122 123 LayoutInflater inflater = LayoutInflater.from(context); 124 mHistoryButton = inflater.inflate(R.layout.recents_history_button, this, false); 125 mHistoryButton.setOnClickListener(new View.OnClickListener() { 126 @Override 127 public void onClick(View v) { 128 EventBus.getDefault().send(new ShowHistoryEvent()); 129 } 130 }); 131 } 132 133 /** Set/get the bsp root node */ 134 public void setTaskStack(TaskStack stack) { 135 RecentsConfiguration config = Recents.getConfiguration(); 136 mStack = stack; 137 if (config.getLaunchState().launchedReuseTaskStackViews) { 138 if (mTaskStackView != null) { 139 // If onRecentsHidden is not triggered, we need to the stack view again here 140 mTaskStackView.reset(); 141 mTaskStackView.setStack(stack); 142 } else { 143 mTaskStackView = new TaskStackView(getContext(), stack); 144 mTaskStackView.setCallbacks(this); 145 addView(mTaskStackView); 146 } 147 } else { 148 if (mTaskStackView != null) { 149 removeView(mTaskStackView); 150 } 151 mTaskStackView = new TaskStackView(getContext(), stack); 152 mTaskStackView.setCallbacks(this); 153 addView(mTaskStackView); 154 } 155 if (indexOfChild(mHistoryButton) == -1) { 156 addView(mHistoryButton); 157 } else { 158 mHistoryButton.bringToFront(); 159 } 160 161 // Trigger a new layout 162 requestLayout(); 163 } 164 165 /** 166 * Returns whether the last task launched was in the freeform stack or not. 167 */ 168 public boolean isLastTaskLaunchedFreeform() { 169 return mLastTaskLaunchedWasFreeform; 170 } 171 172 /** 173 * Returns the currently set task stack. 174 */ 175 public TaskStack getTaskStack() { 176 return mStack; 177 } 178 179 /** Gets the next task in the stack - or if the last - the top task */ 180 public Task getNextTaskOrTopTask(Task taskToSearch) { 181 Task returnTask = null; 182 boolean found = false; 183 if (mTaskStackView != null) { 184 TaskStack stack = mTaskStackView.getStack(); 185 ArrayList<Task> taskList = stack.getStackTasks(); 186 // Iterate the stack views and try and find the focused task 187 for (int j = taskList.size() - 1; j >= 0; --j) { 188 Task task = taskList.get(j); 189 // Return the next task in the line. 190 if (found) 191 return task; 192 // Remember the first possible task as the top task. 193 if (returnTask == null) 194 returnTask = task; 195 if (task == taskToSearch) 196 found = true; 197 } 198 } 199 return returnTask; 200 } 201 202 /** Launches the focused task from the first stack if possible */ 203 public boolean launchFocusedTask() { 204 if (mTaskStackView != null) { 205 TaskStack stack = mTaskStackView.getStack(); 206 Task task = mTaskStackView.getFocusedTask(); 207 if (task != null) { 208 TaskView taskView = mTaskStackView.getChildViewForTask(task); 209 onTaskViewClicked(mTaskStackView, taskView, stack, task, false, null, 210 INVALID_STACK_ID); 211 return true; 212 } 213 } 214 return false; 215 } 216 217 /** Launches a given task. */ 218 public boolean launchTask(Task task, Rect taskBounds, int destinationStack) { 219 if (mTaskStackView != null) { 220 TaskStack stack = mTaskStackView.getStack(); 221 // Iterate the stack views and try and find the given task. 222 List<TaskView> taskViews = mTaskStackView.getTaskViews(); 223 int taskViewCount = taskViews.size(); 224 for (int j = 0; j < taskViewCount; j++) { 225 TaskView tv = taskViews.get(j); 226 if (tv.getTask() == task) { 227 onTaskViewClicked(mTaskStackView, tv, stack, task, false, 228 taskBounds, destinationStack); 229 return true; 230 } 231 } 232 } 233 return false; 234 } 235 236 /** Requests all task stacks to start their enter-recents animation */ 237 public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { 238 // We have to increment/decrement the post animation trigger in case there are no children 239 // to ensure that it runs 240 ctx.postAnimationTrigger.increment(); 241 if (mTaskStackView != null) { 242 mTaskStackView.startEnterRecentsAnimation(ctx); 243 } 244 ctx.postAnimationTrigger.decrement(); 245 } 246 247 /** Requests all task stacks to start their exit-recents animation */ 248 public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { 249 // We have to increment/decrement the post animation trigger in case there are no children 250 // to ensure that it runs 251 ctx.postAnimationTrigger.increment(); 252 if (mTaskStackView != null) { 253 mTaskStackView.startExitToHomeAnimation(ctx); 254 } 255 ctx.postAnimationTrigger.decrement(); 256 257 // Hide the history button 258 int taskViewExitToHomeDuration = getResources().getInteger( 259 R.integer.recents_task_exit_to_home_duration); 260 hideHistoryButton(taskViewExitToHomeDuration); 261 262 // If we are going home, cancel the previous task's window transition 263 EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null)); 264 265 // Notify sof the exit animation 266 EventBus.getDefault().send(new DismissRecentsToHomeAnimationStarted()); 267 } 268 269 /** Adds the search bar */ 270 public void setSearchBar(RecentsAppWidgetHostView searchBar) { 271 // Remove the previous search bar if one exists 272 if (mSearchBar != null && indexOfChild(mSearchBar) > -1) { 273 removeView(mSearchBar); 274 } 275 // Add the new search bar 276 if (searchBar != null) { 277 mSearchBar = searchBar; 278 addView(mSearchBar); 279 } 280 } 281 282 /** Returns whether there is currently a search bar */ 283 public boolean hasValidSearchBar() { 284 return mSearchBar != null && !mSearchBar.isReinflateRequired(); 285 } 286 287 /** Sets the visibility of the search bar */ 288 public void setSearchBarVisibility(int visibility) { 289 if (mSearchBar != null) { 290 mSearchBar.setVisibility(visibility); 291 // Always bring the search bar to the top 292 mSearchBar.bringToFront(); 293 } 294 } 295 296 /** 297 * Returns the last known system insets. 298 */ 299 public Rect getSystemInsets() { 300 return mSystemInsets; 301 } 302 303 @Override 304 protected void onAttachedToWindow() { 305 EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1); 306 EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 1); 307 super.onAttachedToWindow(); 308 } 309 310 @Override 311 protected void onDetachedFromWindow() { 312 super.onDetachedFromWindow(); 313 EventBus.getDefault().unregister(this); 314 EventBus.getDefault().unregister(mTouchHandler); 315 } 316 317 /** 318 * This is called with the full size of the window since we are handling our own insets. 319 */ 320 @Override 321 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 322 RecentsConfiguration config = Recents.getConfiguration(); 323 int width = MeasureSpec.getSize(widthMeasureSpec); 324 int height = MeasureSpec.getSize(heightMeasureSpec); 325 326 // Get the search bar bounds and measure the search bar layout 327 Rect searchBarSpaceBounds = new Rect(); 328 if (mSearchBar != null) { 329 config.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top, 330 searchBarSpaceBounds); 331 mSearchBar.measure( 332 MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY), 333 MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY)); 334 } 335 336 Rect taskStackBounds = new Rect(); 337 config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top, 338 mSystemInsets.right, searchBarSpaceBounds, taskStackBounds); 339 if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) { 340 mTaskStackView.setTaskStackBounds(taskStackBounds, mSystemInsets); 341 mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec); 342 } 343 344 if (mDragView != null) { 345 Rect taskRect = mTaskStackView.mLayoutAlgorithm.mTaskRect; 346 mDragView.measure( 347 MeasureSpec.makeMeasureSpec(taskRect.width(), MeasureSpec.AT_MOST), 348 MeasureSpec.makeMeasureSpec(taskRect.height(), MeasureSpec.AT_MOST)); 349 } 350 351 // Measure the history button with the full space above the stack, but width-constrained 352 // to the stack 353 Rect stackRect = mTaskStackView.mLayoutAlgorithm.mCurrentStackRect; 354 measureChild(mHistoryButton, 355 MeasureSpec.makeMeasureSpec(stackRect.width(), MeasureSpec.EXACTLY), 356 MeasureSpec.makeMeasureSpec(mTaskStackView.mLayoutAlgorithm.getStackTopOffset(), 357 MeasureSpec.EXACTLY)); 358 setMeasuredDimension(width, height); 359 } 360 361 /** 362 * This is called with the full size of the window since we are handling our own insets. 363 */ 364 @Override 365 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 366 RecentsConfiguration config = Recents.getConfiguration(); 367 368 // Get the search bar bounds so that we lay it out 369 Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight()); 370 Rect searchBarSpaceBounds = new Rect(); 371 if (mSearchBar != null) { 372 config.getSearchBarBounds(measuredRect, 373 mSystemInsets.top, searchBarSpaceBounds); 374 mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top, 375 searchBarSpaceBounds.right, searchBarSpaceBounds.bottom); 376 } 377 378 if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) { 379 mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight()); 380 } 381 382 if (mDragView != null) { 383 mDragView.layout(left, top, left + mDragView.getMeasuredWidth(), 384 top + mDragView.getMeasuredHeight()); 385 } 386 387 // Layout the history button left-aligned with the stack, but offset from the top of the 388 // view 389 Rect stackRect = mTaskStackView.mLayoutAlgorithm.mCurrentStackRect; 390 mHistoryButton.layout(stackRect.left, top + mSystemInsets.top, 391 stackRect.left + mHistoryButton.getMeasuredWidth(), 392 top + mSystemInsets.top + mHistoryButton.getMeasuredHeight()); 393 394 if (mAwaitingFirstLayout) { 395 mAwaitingFirstLayout = false; 396 397 // If launched via dragging from the nav bar, then we should translate the whole view 398 // down offscreen 399 RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); 400 if (launchState.launchedViaDragGesture) { 401 setTranslationY(getMeasuredHeight()); 402 } 403 } 404 } 405 406 @Override 407 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 408 mSystemInsets.set(insets.getSystemWindowInsets()); 409 requestLayout(); 410 return insets; 411 } 412 413 @Override 414 public boolean onInterceptTouchEvent(MotionEvent ev) { 415 return mTouchHandler.onInterceptTouchEvent(ev); 416 } 417 418 @Override 419 public boolean onTouchEvent(MotionEvent ev) { 420 return mTouchHandler.onTouchEvent(ev); 421 } 422 423 @Override 424 protected void dispatchDraw(Canvas canvas) { 425 super.dispatchDraw(canvas); 426 for (int i = mVisibleDockStates.length - 1; i >= 0; i--) { 427 Drawable d = mVisibleDockStates[i].viewState.dockAreaOverlay; 428 if (d.getAlpha() > 0) { 429 d.draw(canvas); 430 } 431 } 432 } 433 434 @Override 435 protected boolean verifyDrawable(Drawable who) { 436 for (int i = mVisibleDockStates.length - 1; i >= 0; i--) { 437 Drawable d = mVisibleDockStates[i].viewState.dockAreaOverlay; 438 if (d == who) { 439 return true; 440 } 441 } 442 return super.verifyDrawable(who); 443 } 444 445 public void disableLayersForOneFrame() { 446 if (mTaskStackView != null) { 447 mTaskStackView.disableLayersForOneFrame(); 448 } 449 } 450 451 /**** TaskStackView.TaskStackCallbacks Implementation ****/ 452 453 @Override 454 public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv, 455 final TaskStack stack, final Task task, final boolean lockToTask, 456 final Rect bounds, int destinationStack) { 457 mLastTaskLaunchedWasFreeform = SystemServicesProxy.isFreeformStack(task.key.stackId); 458 mTransitionHelper.launchTaskFromRecents(stack, task, stackView, tv, lockToTask, bounds, 459 destinationStack); 460 } 461 462 /**** EventBus Events ****/ 463 464 public final void onBusEvent(DragStartEvent event) { 465 // Add the drag view 466 mDragView = event.dragView; 467 addView(mDragView); 468 469 updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(), 470 TaskStack.DockState.NONE.viewState.dockAreaAlpha); 471 } 472 473 public final void onBusEvent(DragDropTargetChangedEvent event) { 474 if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) { 475 updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(), 476 TaskStack.DockState.NONE.viewState.dockAreaAlpha); 477 } else { 478 final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; 479 updateVisibleDockRegions(new TaskStack.DockState[] {dockState}, -1); 480 } 481 } 482 483 public final void onBusEvent(final DragEndEvent event) { 484 final Runnable cleanUpRunnable = new Runnable() { 485 @Override 486 public void run() { 487 // Remove the drag view 488 removeView(mDragView); 489 mDragView = null; 490 } 491 }; 492 493 // Animate the overlay alpha back to 0 494 updateVisibleDockRegions(null, -1); 495 496 if (event.dropTarget == null) { 497 // No drop targets for hit, so just animate the task back to its place 498 event.postAnimationTrigger.increment(); 499 event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { 500 @Override 501 public void run() { 502 cleanUpRunnable.run(); 503 } 504 }); 505 // Animate the task back to where it was before then clean up afterwards 506 TaskViewTransform taskTransform = new TaskViewTransform(); 507 TaskStackLayoutAlgorithm layoutAlgorithm = mTaskStackView.getStackAlgorithm(); 508 layoutAlgorithm.getStackTransform(event.task, 509 mTaskStackView.getScroller().getStackScroll(), taskTransform, null); 510 event.dragView.animate() 511 .scaleX(taskTransform.scale) 512 .scaleY(taskTransform.scale) 513 .translationX((layoutAlgorithm.mTaskRect.left - event.dragView.getLeft()) 514 + taskTransform.translationX) 515 .translationY((layoutAlgorithm.mTaskRect.top - event.dragView.getTop()) 516 + taskTransform.translationY) 517 .setDuration(175) 518 .setInterpolator(mFastOutSlowInInterpolator) 519 .withEndAction(event.postAnimationTrigger.decrementAsRunnable()) 520 .start(); 521 522 } else if (event.dropTarget instanceof TaskStack.DockState) { 523 final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; 524 525 // For now, just remove the drag view and the original task 526 // TODO: Animate the task to the drop target rect before launching it above 527 cleanUpRunnable.run(); 528 529 // Dock the task and launch it 530 SystemServicesProxy ssp = Recents.getSystemServices(); 531 ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode); 532 launchTask(event.task, null, INVALID_STACK_ID); 533 534 } else { 535 // We dropped on another drop target, so just add the cleanup to the post animation 536 // trigger 537 event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { 538 @Override 539 public void run() { 540 cleanUpRunnable.run(); 541 } 542 }); 543 } 544 } 545 546 public final void onBusEvent(DraggingInRecentsEvent event) { 547 if (mTaskStackView.getTaskViews().size() > 0) { 548 setTranslationY(event.distanceFromTop - mTaskStackView.getTaskViews().get(0).getY()); 549 } 550 } 551 552 public final void onBusEvent(DraggingInRecentsEndedEvent event) { 553 animate().translationY(0f); 554 } 555 556 public final void onBusEvent(ShowHistoryEvent event) { 557 // Hide the history button when the history view is shown 558 hideHistoryButton(mHistoryTransitionDuration); 559 } 560 561 public final void onBusEvent(HideHistoryEvent event) { 562 // Show the history button when the history view is hidden 563 showHistoryButton(mHistoryTransitionDuration); 564 } 565 566 public final void onBusEvent(ShowHistoryButtonEvent event) { 567 showHistoryButton(150); 568 } 569 570 public final void onBusEvent(HideHistoryButtonEvent event) { 571 hideHistoryButton(100); 572 } 573 574 public final void onBusEvent(DebugFlagsChangedEvent event) { 575 RecentsDebugFlags debugFlags = Recents.getDebugFlags(); 576 if (!debugFlags.isHistoryEnabled()) { 577 hideHistoryButton(100); 578 } 579 } 580 581 /** 582 * Shows the history button. 583 */ 584 private void showHistoryButton(int duration) { 585 RecentsDebugFlags debugFlags = Recents.getDebugFlags(); 586 if (!debugFlags.isHistoryEnabled()) { 587 return; 588 } 589 590 mHistoryButton.setVisibility(View.VISIBLE); 591 mHistoryButton.animate() 592 .alpha(1f) 593 .setDuration(duration) 594 .setInterpolator(mFastOutSlowInInterpolator) 595 .withLayer() 596 .start(); 597 } 598 599 /** 600 * Hides the history button. 601 */ 602 private void hideHistoryButton(int duration) { 603 mHistoryButton.animate() 604 .alpha(0f) 605 .setDuration(duration) 606 .setInterpolator(mFastOutLinearInInterpolator) 607 .withEndAction(new Runnable() { 608 @Override 609 public void run() { 610 mHistoryButton.setVisibility(View.INVISIBLE); 611 } 612 }) 613 .withLayer() 614 .start(); 615 } 616 617 /** 618 * Updates the dock region to match the specified dock state. 619 */ 620 private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates, int overrideAlpha) { 621 ArraySet<TaskStack.DockState> newDockStatesSet = new ArraySet<>(); 622 if (newDockStates != null) { 623 for (TaskStack.DockState dockState : newDockStates) { 624 newDockStatesSet.add(dockState); 625 } 626 } 627 for (TaskStack.DockState dockState : mVisibleDockStates) { 628 TaskStack.DockState.ViewState viewState = dockState.viewState; 629 if (newDockStates == null || !newDockStatesSet.contains(dockState)) { 630 // This is no longer visible, so hide it 631 viewState.startAlphaAnimation(0, 150); 632 } else { 633 // This state is now visible, update the bounds and show it 634 int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha); 635 viewState.dockAreaOverlay.setBounds( 636 dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight())); 637 viewState.dockAreaOverlay.setCallback(this); 638 viewState.startAlphaAnimation(alpha, 150); 639 } 640 } 641 } 642 643 public final void onBusEvent(RecentsVisibilityChangedEvent event) { 644 if (!event.visible) { 645 // Reset the view state 646 mAwaitingFirstLayout = true; 647 mLastTaskLaunchedWasFreeform = false; 648 } 649 } 650} 651