DividerView.java revision cdb06caebb5f6f554b2ed8c76963970d8cc0ab54
1/* 2 * Copyright (C) 2015 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.stackdivider; 18 19import android.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.animation.ValueAnimator; 22import android.animation.ValueAnimator.AnimatorUpdateListener; 23import android.annotation.Nullable; 24import android.app.ActivityManager.StackId; 25import android.content.Context; 26import android.content.res.Configuration; 27import android.graphics.Rect; 28import android.graphics.Region.Op; 29import android.hardware.display.DisplayManager; 30import android.util.AttributeSet; 31import android.view.Display; 32import android.view.DisplayInfo; 33import android.view.MotionEvent; 34import android.view.PointerIcon; 35import android.view.VelocityTracker; 36import android.view.View; 37import android.view.View.OnTouchListener; 38import android.view.ViewConfiguration; 39import android.view.ViewTreeObserver.InternalInsetsInfo; 40import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; 41import android.view.WindowInsets; 42import android.view.WindowManager; 43import android.view.animation.AnimationUtils; 44import android.view.animation.Interpolator; 45import android.view.animation.PathInterpolator; 46import android.widget.FrameLayout; 47 48import com.android.internal.policy.DividerSnapAlgorithm; 49import com.android.internal.policy.DockedDividerUtils; 50import com.android.systemui.R; 51import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; 52import com.android.systemui.recents.events.EventBus; 53import com.android.systemui.recents.events.activity.DockingTopTaskEvent; 54import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; 55import com.android.systemui.recents.events.ui.RecentsDrawnEvent; 56import com.android.systemui.statusbar.FlingAnimationUtils; 57import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; 58 59import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW; 60import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW; 61 62/** 63 * Docked stack divider. 64 */ 65public class DividerView extends FrameLayout implements OnTouchListener, 66 OnComputeInternalInsetsListener { 67 68 static final long TOUCH_ANIMATION_DURATION = 150; 69 static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; 70 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = 71 new PathInterpolator(0.3f, 0f, 0.1f, 1f); 72 73 private static final String TAG = "DividerView"; 74 75 private static final int TASK_POSITION_SAME = Integer.MAX_VALUE; 76 private static final float DIM_START_FRACTION = 0.5f; 77 private static final float DIM_DAMP_FACTOR = 1.7f; 78 79 private static final PathInterpolator SLOWDOWN_INTERPOLATOR = 80 new PathInterpolator(0.5f, 1f, 0.5f, 1f); 81 82 private DividerHandleView mHandle; 83 private View mBackground; 84 private int mStartX; 85 private int mStartY; 86 private int mStartPosition; 87 private int mDockSide; 88 private final int[] mTempInt2 = new int[2]; 89 private boolean mMoving; 90 private int mTouchSlop; 91 92 private int mDividerInsets; 93 private int mDisplayWidth; 94 private int mDisplayHeight; 95 private int mDividerWindowWidth; 96 private int mDividerSize; 97 private int mTouchElevation; 98 99 private final Rect mDockedRect = new Rect(); 100 private final Rect mDockedTaskRect = new Rect(); 101 private final Rect mOtherTaskRect = new Rect(); 102 private final Rect mOtherRect = new Rect(); 103 private final Rect mDockedInsetRect = new Rect(); 104 private final Rect mOtherInsetRect = new Rect(); 105 private final Rect mLastResizeRect = new Rect(); 106 private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance(); 107 private Interpolator mFastOutSlowInInterpolator; 108 private DividerWindowManager mWindowManager; 109 private VelocityTracker mVelocityTracker; 110 private FlingAnimationUtils mFlingAnimationUtils; 111 private DividerSnapAlgorithm mSnapAlgorithm; 112 private final Rect mStableInsets = new Rect(); 113 114 private boolean mAnimateAfterRecentsDrawn; 115 private boolean mGrowAfterRecentsDrawn; 116 private boolean mGrowRecents; 117 118 public DividerView(Context context) { 119 super(context); 120 } 121 122 public DividerView(Context context, @Nullable AttributeSet attrs) { 123 super(context, attrs); 124 } 125 126 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 127 super(context, attrs, defStyleAttr); 128 } 129 130 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, 131 int defStyleRes) { 132 super(context, attrs, defStyleAttr, defStyleRes); 133 } 134 135 @Override 136 protected void onFinishInflate() { 137 super.onFinishInflate(); 138 mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle); 139 mBackground = findViewById(R.id.docked_divider_background); 140 mHandle.setOnTouchListener(this); 141 mDividerWindowWidth = getResources().getDimensionPixelSize( 142 com.android.internal.R.dimen.docked_stack_divider_thickness); 143 mDividerInsets = getResources().getDimensionPixelSize( 144 com.android.internal.R.dimen.docked_stack_divider_insets); 145 mDividerSize = mDividerWindowWidth - 2 * mDividerInsets; 146 mTouchElevation = getResources().getDimensionPixelSize( 147 R.dimen.docked_stack_divider_lift_elevation); 148 mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow); 149 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(), 150 android.R.interpolator.fast_out_slow_in); 151 mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); 152 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f); 153 updateDisplayInfo(); 154 boolean landscape = getResources().getConfiguration().orientation 155 == Configuration.ORIENTATION_LANDSCAPE; 156 mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(), 157 landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW)); 158 getViewTreeObserver().addOnComputeInternalInsetsListener(this); 159 } 160 161 @Override 162 protected void onAttachedToWindow() { 163 super.onAttachedToWindow(); 164 EventBus.getDefault().register(this); 165 } 166 167 @Override 168 protected void onDetachedFromWindow() { 169 super.onDetachedFromWindow(); 170 EventBus.getDefault().unregister(this); 171 } 172 173 @Override 174 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 175 mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(), 176 insets.getStableInsetRight(), insets.getStableInsetBottom()); 177 return super.onApplyWindowInsets(insets); 178 } 179 180 public void setWindowManager(DividerWindowManager windowManager) { 181 mWindowManager = windowManager; 182 } 183 184 public WindowManagerProxy getWindowManagerProxy() { 185 return mWindowManagerProxy; 186 } 187 188 public boolean startDragging(boolean animate, boolean touching) { 189 if (touching) { 190 mHandle.setTouching(true, animate); 191 } 192 mDockSide = mWindowManagerProxy.getDockSide(); 193 getSnapAlgorithm(); 194 if (mDockSide != WindowManager.DOCKED_INVALID) { 195 mWindowManagerProxy.setResizing(true); 196 mWindowManager.setSlippery(false); 197 if (touching) { 198 liftBackground(); 199 } 200 return true; 201 } else { 202 return false; 203 } 204 } 205 206 public void stopDragging(int position, float velocity, boolean avoidDismissStart) { 207 mHandle.setTouching(false, true /* animate */); 208 fling(position, velocity, avoidDismissStart); 209 mWindowManager.setSlippery(true); 210 releaseBackground(); 211 } 212 213 public void stopDragging(int position, SnapTarget target, long duration, 214 Interpolator interpolator) { 215 mHandle.setTouching(false, true /* animate */); 216 flingTo(position, target, duration, interpolator); 217 mWindowManager.setSlippery(true); 218 releaseBackground(); 219 } 220 221 public DividerSnapAlgorithm getSnapAlgorithm() { 222 if (mSnapAlgorithm == null) { 223 mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth, 224 mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets); 225 } 226 return mSnapAlgorithm; 227 } 228 229 public int getCurrentPosition() { 230 getLocationOnScreen(mTempInt2); 231 if (isHorizontalDivision()) { 232 return mTempInt2[1] + mDividerInsets; 233 } else { 234 return mTempInt2[0] + mDividerInsets; 235 } 236 } 237 238 @Override 239 public boolean onTouch(View v, MotionEvent event) { 240 convertToScreenCoordinates(event); 241 final int action = event.getAction() & MotionEvent.ACTION_MASK; 242 switch (action) { 243 case MotionEvent.ACTION_DOWN: 244 mVelocityTracker = VelocityTracker.obtain(); 245 mVelocityTracker.addMovement(event); 246 mStartX = (int) event.getX(); 247 mStartY = (int) event.getY(); 248 boolean result = startDragging(true /* animate */, true /* touching */); 249 mStartPosition = getCurrentPosition(); 250 mMoving = false; 251 return result; 252 case MotionEvent.ACTION_MOVE: 253 mVelocityTracker.addMovement(event); 254 int x = (int) event.getX(); 255 int y = (int) event.getY(); 256 boolean exceededTouchSlop = 257 isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop 258 || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop); 259 if (!mMoving && exceededTouchSlop) { 260 mStartX = x; 261 mStartY = y; 262 mMoving = true; 263 } 264 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) { 265 int position = calculatePosition(x, y); 266 SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, 267 0 /* velocity */, false /* hardDismiss */); 268 resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget); 269 } 270 break; 271 case MotionEvent.ACTION_UP: 272 case MotionEvent.ACTION_CANCEL: 273 mVelocityTracker.addMovement(event); 274 275 x = (int) event.getRawX(); 276 y = (int) event.getRawY(); 277 278 mVelocityTracker.computeCurrentVelocity(1000); 279 int position = calculatePosition(x, y); 280 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity() 281 : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */); 282 mMoving = false; 283 break; 284 } 285 return true; 286 } 287 288 private void convertToScreenCoordinates(MotionEvent event) { 289 event.setLocation(event.getRawX(), event.getRawY()); 290 } 291 292 private void fling(int position, float velocity, boolean avoidDismissStart) { 293 SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity); 294 if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) { 295 snapTarget = mSnapAlgorithm.getFirstSplitTarget(); 296 } 297 ValueAnimator anim = getFlingAnimator(position, snapTarget); 298 mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity); 299 anim.start(); 300 } 301 302 private void flingTo(int position, SnapTarget target, long duration, 303 Interpolator interpolator) { 304 ValueAnimator anim = getFlingAnimator(position, target); 305 anim.setDuration(duration); 306 anim.setInterpolator(interpolator); 307 anim.start(); 308 } 309 310 private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) { 311 ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position); 312 anim.addUpdateListener(new AnimatorUpdateListener() { 313 @Override 314 public void onAnimationUpdate(ValueAnimator animation) { 315 resizeStack((Integer) animation.getAnimatedValue(), 316 animation.getAnimatedFraction() == 1f 317 ? TASK_POSITION_SAME 318 : snapTarget.position, snapTarget); 319 } 320 }); 321 anim.addListener(new AnimatorListenerAdapter() { 322 @Override 323 public void onAnimationEnd(Animator animation) { 324 commitSnapFlags(snapTarget); 325 mWindowManagerProxy.setResizing(false); 326 mDockSide = WindowManager.DOCKED_INVALID; 327 } 328 }); 329 return anim; 330 } 331 332 private void commitSnapFlags(SnapTarget target) { 333 if (target.flag == SnapTarget.FLAG_NONE) { 334 return; 335 } 336 boolean dismissOrMaximize; 337 if (target.flag == SnapTarget.FLAG_DISMISS_START) { 338 dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT 339 || mDockSide == WindowManager.DOCKED_TOP; 340 } else { 341 dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT 342 || mDockSide == WindowManager.DOCKED_BOTTOM; 343 } 344 if (dismissOrMaximize) { 345 mWindowManagerProxy.dismissDockedStack(); 346 } else { 347 mWindowManagerProxy.maximizeDockedStack(); 348 } 349 mWindowManagerProxy.setResizeDimLayer(false, -1, 0f); 350 } 351 352 private void liftBackground() { 353 if (isHorizontalDivision()) { 354 mBackground.animate().scaleY(1.4f); 355 } else { 356 mBackground.animate().scaleX(1.4f); 357 } 358 mBackground.animate() 359 .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR) 360 .setDuration(TOUCH_ANIMATION_DURATION) 361 .translationZ(mTouchElevation) 362 .start(); 363 364 // Lift handle as well so it doesn't get behind the background, even though it doesn't 365 // cast shadow. 366 mHandle.animate() 367 .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR) 368 .setDuration(TOUCH_ANIMATION_DURATION) 369 .translationZ(mTouchElevation) 370 .start(); 371 } 372 373 private void releaseBackground() { 374 mBackground.animate() 375 .setInterpolator(mFastOutSlowInInterpolator) 376 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) 377 .translationZ(0) 378 .scaleX(1f) 379 .scaleY(1f) 380 .start(); 381 mHandle.animate() 382 .setInterpolator(mFastOutSlowInInterpolator) 383 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) 384 .translationZ(0) 385 .start(); 386 } 387 388 @Override 389 protected void onConfigurationChanged(Configuration newConfig) { 390 super.onConfigurationChanged(newConfig); 391 updateDisplayInfo(); 392 } 393 394 private void updateDisplayInfo() { 395 final DisplayManager displayManager = 396 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); 397 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 398 final DisplayInfo info = new DisplayInfo(); 399 display.getDisplayInfo(info); 400 mDisplayWidth = info.logicalWidth; 401 mDisplayHeight = info.logicalHeight; 402 mSnapAlgorithm = null; 403 } 404 405 private int calculatePosition(int touchX, int touchY) { 406 return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX); 407 } 408 409 public boolean isHorizontalDivision() { 410 return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 411 } 412 413 private int calculateXPosition(int touchX) { 414 return mStartPosition + touchX - mStartX; 415 } 416 417 private int calculateYPosition(int touchY) { 418 return mStartPosition + touchY - mStartY; 419 } 420 421 private void alignTopLeft(Rect containingRect, Rect rect) { 422 int width = rect.width(); 423 int height = rect.height(); 424 rect.set(containingRect.left, containingRect.top, 425 containingRect.left + width, containingRect.top + height); 426 } 427 428 private void alignBottomRight(Rect containingRect, Rect rect) { 429 int width = rect.width(); 430 int height = rect.height(); 431 rect.set(containingRect.right - width, containingRect.bottom - height, 432 containingRect.right, containingRect.bottom); 433 } 434 435 public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) { 436 DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, mDisplayWidth, 437 mDisplayHeight, mDividerSize); 438 } 439 440 public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) { 441 calculateBoundsForPosition(position, mDockSide, mDockedRect); 442 443 if (mDockedRect.equals(mLastResizeRect)) { 444 return; 445 } 446 447 // Make sure shadows are updated 448 mBackground.invalidate(); 449 450 mLastResizeRect.set(mDockedRect); 451 if (taskPosition != TASK_POSITION_SAME) { 452 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide), 453 mOtherRect); 454 int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide); 455 int taskPositionDocked = 456 restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget); 457 int taskPositionOther = 458 restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget); 459 calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect); 460 calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect); 461 alignTopLeft(mDockedRect, mDockedTaskRect); 462 alignTopLeft(mOtherRect, mOtherTaskRect); 463 mDockedInsetRect.set(mDockedTaskRect); 464 mOtherInsetRect.set(mOtherTaskRect); 465 if (dockSideTopLeft(mDockSide)) { 466 alignTopLeft(mDockedRect, mDockedInsetRect); 467 alignBottomRight(mOtherRect, mOtherInsetRect); 468 } else { 469 alignBottomRight(mDockedRect, mDockedInsetRect); 470 alignTopLeft(mOtherRect, mOtherInsetRect); 471 } 472 applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position, 473 taskPositionDocked); 474 applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position, 475 taskPositionOther); 476 mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect, 477 mOtherTaskRect, mOtherInsetRect); 478 } else { 479 mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null); 480 } 481 float fraction = mSnapAlgorithm.calculateDismissingFraction(position); 482 fraction = Math.max(0, 483 Math.min((fraction / DIM_START_FRACTION - 1f) / DIM_DAMP_FACTOR, 1f)); 484 mWindowManagerProxy.setResizeDimLayer(fraction != 0f, 485 getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)), 486 fraction); 487 } 488 489 /** 490 * When the snap target is dismissing one side, make sure that the dismissing side doesn't get 491 * 0 size. 492 */ 493 private int restrictDismissingTaskPosition(int taskPosition, int dockSide, 494 SnapTarget snapTarget) { 495 if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) { 496 return mSnapAlgorithm.getFirstSplitTarget().position; 497 } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END 498 && dockSideBottomRight(dockSide)) { 499 return mSnapAlgorithm.getLastSplitTarget().position; 500 } else { 501 return taskPosition; 502 } 503 } 504 505 /** 506 * Applies a parallax to the task when dismissing. 507 */ 508 private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget, 509 int position, int taskPosition) { 510 float fraction = Math.min(1, Math.max(0, 511 mSnapAlgorithm.calculateDismissingFraction(position))); 512 SnapTarget dismissTarget = null; 513 SnapTarget splitTarget = null; 514 if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START 515 || snapTarget == mSnapAlgorithm.getFirstSplitTarget()) 516 && dockSideTopLeft(dockSide)) { 517 dismissTarget = mSnapAlgorithm.getDismissStartTarget(); 518 splitTarget = mSnapAlgorithm.getFirstSplitTarget(); 519 } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END 520 || snapTarget == mSnapAlgorithm.getLastSplitTarget()) 521 && dockSideBottomRight(dockSide)) { 522 dismissTarget = mSnapAlgorithm.getDismissEndTarget(); 523 splitTarget = mSnapAlgorithm.getLastSplitTarget(); 524 } 525 if (dismissTarget != null && fraction > 0f 526 && isDismissing(splitTarget, position, dockSide)) { 527 fraction = calculateParallaxDismissingFraction(fraction); 528 int offsetPosition = (int) (taskPosition + 529 fraction * (dismissTarget.position - splitTarget.position)); 530 int width = taskRect.width(); 531 int height = taskRect.height(); 532 switch (dockSide) { 533 case WindowManager.DOCKED_LEFT: 534 taskRect.left = offsetPosition - width; 535 taskRect.right = offsetPosition; 536 break; 537 case WindowManager.DOCKED_RIGHT: 538 taskRect.left = offsetPosition + mDividerSize; 539 taskRect.right = offsetPosition + width + mDividerSize; 540 break; 541 case WindowManager.DOCKED_TOP: 542 taskRect.top = offsetPosition - height; 543 taskRect.bottom = offsetPosition; 544 break; 545 case WindowManager.DOCKED_BOTTOM: 546 taskRect.top = offsetPosition + mDividerSize; 547 taskRect.bottom = offsetPosition + height + mDividerSize; 548 break; 549 } 550 } 551 } 552 553 /** 554 * @return for a specified {@code fraction}, this returns an adjusted value that simulates a 555 * slowing down parallax effect 556 */ 557 private static float calculateParallaxDismissingFraction(float fraction) { 558 return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f; 559 } 560 561 private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) { 562 if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) { 563 return position < snapTarget.position; 564 } else { 565 return position > snapTarget.position; 566 } 567 } 568 569 private int getStackIdForDismissTarget(SnapTarget dismissTarget) { 570 if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && 571 (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) { 572 return StackId.DOCKED_STACK_ID; 573 } else { 574 return StackId.FULLSCREEN_WORKSPACE_STACK_ID; 575 } 576 } 577 578 /** 579 * @return true if and only if {@code dockSide} is top or left 580 */ 581 private static boolean dockSideTopLeft(int dockSide) { 582 return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT; 583 } 584 585 /** 586 * @return true if and only if {@code dockSide} is bottom or right 587 */ 588 private static boolean dockSideBottomRight(int dockSide) { 589 return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT; 590 } 591 592 @Override 593 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) { 594 inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); 595 inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), 596 mHandle.getBottom()); 597 inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(), 598 mBackground.getRight(), mBackground.getBottom(), Op.UNION); 599 } 600 601 public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) { 602 if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP 603 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) { 604 mGrowAfterRecentsDrawn = true; 605 startDragging(false /* animate */, false /* touching */); 606 } 607 } 608 609 public final void onBusEvent(DockingTopTaskEvent dockingEvent) { 610 if (dockingEvent.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) { 611 mGrowAfterRecentsDrawn = false; 612 mAnimateAfterRecentsDrawn = true; 613 startDragging(false /* animate */, false /* touching */); 614 } 615 } 616 617 public final void onBusEvent(RecentsDrawnEvent drawnEvent) { 618 if (mAnimateAfterRecentsDrawn) { 619 mAnimateAfterRecentsDrawn = false; 620 stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250, 621 TOUCH_RESPONSE_INTERPOLATOR); 622 } 623 if (mGrowAfterRecentsDrawn) { 624 mGrowAfterRecentsDrawn = false; 625 stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250, 626 TOUCH_RESPONSE_INTERPOLATOR); 627 } 628 } 629} 630