1 2 /* 3 * Copyright (C) 2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.launcher3.dragndrop; 19 20 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; 21 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; 22 23 import android.animation.Animator; 24 import android.animation.AnimatorListenerAdapter; 25 import android.animation.TimeInterpolator; 26 import android.animation.ValueAnimator; 27 import android.animation.ValueAnimator.AnimatorUpdateListener; 28 import android.content.Context; 29 import android.content.res.Resources; 30 import android.graphics.Canvas; 31 import android.graphics.Rect; 32 import android.util.AttributeSet; 33 import android.view.KeyEvent; 34 import android.view.MotionEvent; 35 import android.view.View; 36 import android.view.accessibility.AccessibilityEvent; 37 import android.view.accessibility.AccessibilityManager; 38 import android.view.animation.Interpolator; 39 40 import com.android.launcher3.AbstractFloatingView; 41 import com.android.launcher3.CellLayout; 42 import com.android.launcher3.DropTargetBar; 43 import com.android.launcher3.Launcher; 44 import com.android.launcher3.R; 45 import com.android.launcher3.ShortcutAndWidgetContainer; 46 import com.android.launcher3.Workspace; 47 import com.android.launcher3.folder.Folder; 48 import com.android.launcher3.graphics.OverviewScrim; 49 import com.android.launcher3.graphics.WorkspaceAndHotseatScrim; 50 import com.android.launcher3.keyboard.ViewGroupFocusHelper; 51 import com.android.launcher3.util.Thunk; 52 import com.android.launcher3.views.BaseDragLayer; 53 54 import java.util.ArrayList; 55 56 /** 57 * A ViewGroup that coordinates dragging across its descendants 58 */ 59 public class DragLayer extends BaseDragLayer<Launcher> { 60 61 public static final int ALPHA_INDEX_OVERLAY = 0; 62 public static final int ALPHA_INDEX_LAUNCHER_LOAD = 1; 63 public static final int ALPHA_INDEX_TRANSITIONS = 2; 64 private static final int ALPHA_CHANNEL_COUNT = 3; 65 66 public static final int ANIMATION_END_DISAPPEAR = 0; 67 public static final int ANIMATION_END_REMAIN_VISIBLE = 2; 68 69 private DragController mDragController; 70 71 // Variables relating to animation of views after drop 72 private ValueAnimator mDropAnim = null; 73 74 @Thunk DragView mDropView = null; 75 @Thunk int mAnchorViewInitialScrollX = 0; 76 @Thunk View mAnchorView = null; 77 78 private boolean mHoverPointClosesFolder = false; 79 80 private int mTopViewIndex; 81 private int mChildCountOnLastUpdate = -1; 82 83 // Related to adjacent page hints 84 private final ViewGroupFocusHelper mFocusIndicatorHelper; 85 private final WorkspaceAndHotseatScrim mWorkspaceScrim; 86 private final OverviewScrim mOverviewScrim; 87 88 // View that should handle move events 89 private View mMoveTarget; 90 91 /** 92 * Used to create a new DragLayer from XML. 93 * 94 * @param context The application's context. 95 * @param attrs The attributes set containing the Workspace's customization values. 96 */ DragLayer(Context context, AttributeSet attrs)97 public DragLayer(Context context, AttributeSet attrs) { 98 super(context, attrs, ALPHA_CHANNEL_COUNT); 99 100 // Disable multitouch across the workspace/all apps/customize tray 101 setMotionEventSplittingEnabled(false); 102 setChildrenDrawingOrderEnabled(true); 103 104 mFocusIndicatorHelper = new ViewGroupFocusHelper(this); 105 mWorkspaceScrim = new WorkspaceAndHotseatScrim(this); 106 mOverviewScrim = new OverviewScrim(this); 107 } 108 setup(DragController dragController, Workspace workspace)109 public void setup(DragController dragController, Workspace workspace) { 110 mDragController = dragController; 111 mWorkspaceScrim.setWorkspace(workspace); 112 mMoveTarget = workspace; 113 recreateControllers(); 114 } 115 116 @Override recreateControllers()117 public void recreateControllers() { 118 mControllers = mActivity.createTouchControllers(); 119 } 120 getFocusIndicatorHelper()121 public ViewGroupFocusHelper getFocusIndicatorHelper() { 122 return mFocusIndicatorHelper; 123 } 124 125 @Override dispatchKeyEvent(KeyEvent event)126 public boolean dispatchKeyEvent(KeyEvent event) { 127 return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); 128 } 129 isEventOverAccessibleDropTargetBar(MotionEvent ev)130 private boolean isEventOverAccessibleDropTargetBar(MotionEvent ev) { 131 return isInAccessibleDrag() && isEventOverView(mActivity.getDropTargetBar(), ev); 132 } 133 134 @Override onInterceptHoverEvent(MotionEvent ev)135 public boolean onInterceptHoverEvent(MotionEvent ev) { 136 if (mActivity == null || mActivity.getWorkspace() == null) { 137 return false; 138 } 139 AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); 140 if (!(topView instanceof Folder)) { 141 return false; 142 } else { 143 AccessibilityManager accessibilityManager = (AccessibilityManager) 144 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 145 if (accessibilityManager.isTouchExplorationEnabled()) { 146 Folder currentFolder = (Folder) topView; 147 final int action = ev.getAction(); 148 boolean isOverFolderOrSearchBar; 149 switch (action) { 150 case MotionEvent.ACTION_HOVER_ENTER: 151 isOverFolderOrSearchBar = isEventOverView(topView, ev) || 152 isEventOverAccessibleDropTargetBar(ev); 153 if (!isOverFolderOrSearchBar) { 154 sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName()); 155 mHoverPointClosesFolder = true; 156 return true; 157 } 158 mHoverPointClosesFolder = false; 159 break; 160 case MotionEvent.ACTION_HOVER_MOVE: 161 isOverFolderOrSearchBar = isEventOverView(topView, ev) || 162 isEventOverAccessibleDropTargetBar(ev); 163 if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) { 164 sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName()); 165 mHoverPointClosesFolder = true; 166 return true; 167 } else if (!isOverFolderOrSearchBar) { 168 return true; 169 } 170 mHoverPointClosesFolder = false; 171 } 172 } 173 } 174 return false; 175 } 176 sendTapOutsideFolderAccessibilityEvent(boolean isEditingName)177 private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) { 178 int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close; 179 sendCustomAccessibilityEvent( 180 this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId)); 181 } 182 183 @Override onHoverEvent(MotionEvent ev)184 public boolean onHoverEvent(MotionEvent ev) { 185 // If we've received this, we've already done the necessary handling 186 // in onInterceptHoverEvent. Return true to consume the event. 187 return false; 188 } 189 190 isInAccessibleDrag()191 private boolean isInAccessibleDrag() { 192 return mActivity.getAccessibilityDelegate().isInAccessibleDrag(); 193 } 194 195 @Override onRequestSendAccessibilityEvent(View child, AccessibilityEvent event)196 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { 197 if (isInAccessibleDrag() && child instanceof DropTargetBar) { 198 return true; 199 } 200 return super.onRequestSendAccessibilityEvent(child, event); 201 } 202 203 @Override addChildrenForAccessibility(ArrayList<View> childrenForAccessibility)204 public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) { 205 View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity, 206 AbstractFloatingView.TYPE_ACCESSIBLE); 207 if (topView != null) { 208 addAccessibleChildToList(topView, childrenForAccessibility); 209 if (isInAccessibleDrag()) { 210 addAccessibleChildToList(mActivity.getDropTargetBar(), childrenForAccessibility); 211 } 212 } else { 213 super.addChildrenForAccessibility(childrenForAccessibility); 214 } 215 } 216 217 @Override dispatchUnhandledMove(View focused, int direction)218 public boolean dispatchUnhandledMove(View focused, int direction) { 219 return super.dispatchUnhandledMove(focused, direction) 220 || mMoveTarget.dispatchUnhandledMove(focused, direction); 221 } 222 223 @Override dispatchTouchEvent(MotionEvent ev)224 public boolean dispatchTouchEvent(MotionEvent ev) { 225 ev.offsetLocation(getTranslationX(), 0); 226 try { 227 return super.dispatchTouchEvent(ev); 228 } finally { 229 ev.offsetLocation(-getTranslationX(), 0); 230 } 231 } 232 animateViewIntoPosition(DragView dragView, final int[] pos, float alpha, float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable, int duration)233 public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha, 234 float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable, 235 int duration) { 236 Rect r = new Rect(); 237 getViewRectRelativeToSelf(dragView, r); 238 final int fromX = r.left; 239 final int fromY = r.top; 240 241 animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY, 242 onFinishRunnable, animationEndStyle, duration, null); 243 } 244 animateViewIntoPosition(DragView dragView, final View child, View anchorView)245 public void animateViewIntoPosition(DragView dragView, final View child, View anchorView) { 246 animateViewIntoPosition(dragView, child, -1, anchorView); 247 } 248 animateViewIntoPosition(DragView dragView, final View child, int duration, View anchorView)249 public void animateViewIntoPosition(DragView dragView, final View child, int duration, 250 View anchorView) { 251 252 ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent(); 253 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 254 parentChildren.measureChild(child); 255 parentChildren.layoutChild(child); 256 257 Rect dragViewBounds = new Rect(); 258 getViewRectRelativeToSelf(dragView, dragViewBounds); 259 final int fromX = dragViewBounds.left; 260 final int fromY = dragViewBounds.top; 261 262 float coord[] = new float[2]; 263 float childScale = child.getScaleX(); 264 265 coord[0] = lp.x + (child.getMeasuredWidth() * (1 - childScale) / 2); 266 coord[1] = lp.y + (child.getMeasuredHeight() * (1 - childScale) / 2); 267 268 // Since the child hasn't necessarily been laid out, we force the lp to be updated with 269 // the correct coordinates (above) and use these to determine the final location 270 float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord); 271 272 // We need to account for the scale of the child itself, as the above only accounts for 273 // for the scale in parents. 274 scale *= childScale; 275 int toX = Math.round(coord[0]); 276 int toY = Math.round(coord[1]); 277 278 float toScale = scale; 279 280 if (child instanceof DraggableView) { 281 // This code is fairly subtle. Please verify drag and drop is pixel-perfect in a number 282 // of scenarios before modifying (from all apps, from workspace, different grid-sizes, 283 // shortcuts from in and out of Launcher etc). 284 DraggableView d = (DraggableView) child; 285 Rect destRect = new Rect(); 286 d.getWorkspaceVisualDragBounds(destRect); 287 288 // In most cases this additional scale factor should be a no-op (1). It mainly accounts 289 // for alternate grids where the source and destination icon sizes are different 290 toScale *= ((1f * destRect.width()) 291 / (dragView.getMeasuredWidth() - dragView.getBlurSizeOutline())); 292 293 // This accounts for the offset of the DragView created by scaling it about its 294 // center as it animates into place. 295 float scaleShiftX = dragView.getMeasuredWidth() * (1 - toScale) / 2; 296 float scaleShiftY = dragView.getMeasuredHeight() * (1 - toScale) / 2; 297 298 toX += scale * destRect.left - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftX; 299 toY += scale * destRect.top - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftY; 300 } 301 302 child.setVisibility(INVISIBLE); 303 Runnable onCompleteRunnable = () -> child.setVisibility(VISIBLE); 304 animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale, 305 onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView); 306 } 307 animateViewIntoPosition(final DragView view, final int fromX, final int fromY, final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY, float finalScaleX, float finalScaleY, Runnable onCompleteRunnable, int animationEndStyle, int duration, View anchorView)308 public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY, 309 final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY, 310 float finalScaleX, float finalScaleY, Runnable onCompleteRunnable, 311 int animationEndStyle, int duration, View anchorView) { 312 Rect from = new Rect(fromX, fromY, fromX + 313 view.getMeasuredWidth(), fromY + view.getMeasuredHeight()); 314 Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight()); 315 animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration, 316 null, null, onCompleteRunnable, animationEndStyle, anchorView); 317 } 318 319 /** 320 * This method animates a view at the end of a drag and drop animation. 321 * 322 * @param view The view to be animated. This view is drawn directly into DragLayer, and so 323 * doesn't need to be a child of DragLayer. 324 * @param from The initial location of the view. Only the left and top parameters are used. 325 * @param to The final location of the view. Only the left and top parameters are used. This 326 * location doesn't account for scaling, and so should be centered about the desired 327 * final location (including scaling). 328 * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates. 329 * @param finalScaleX The final scale of the view. The view is scaled about its center. 330 * @param finalScaleY The final scale of the view. The view is scaled about its center. 331 * @param duration The duration of the animation. 332 * @param motionInterpolator The interpolator to use for the location of the view. 333 * @param alphaInterpolator The interpolator to use for the alpha of the view. 334 * @param onCompleteRunnable Optional runnable to run on animation completion. 335 * @param animationEndStyle Whether or not to fade out the view once the animation completes. 336 * {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}. 337 * @param anchorView If not null, this represents the view which the animated view stays 338 * anchored to in case scrolling is currently taking place. Note: currently this is 339 * only used for the X dimension for the case of the workspace. 340 */ animateView(final DragView view, final Rect from, final Rect to, final float finalAlpha, final float initScaleX, final float initScaleY, final float finalScaleX, final float finalScaleY, int duration, final Interpolator motionInterpolator, final Interpolator alphaInterpolator, final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView)341 public void animateView(final DragView view, final Rect from, final Rect to, 342 final float finalAlpha, final float initScaleX, final float initScaleY, 343 final float finalScaleX, final float finalScaleY, int duration, 344 final Interpolator motionInterpolator, final Interpolator alphaInterpolator, 345 final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) { 346 347 // Calculate the duration of the animation based on the object's distance 348 final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top); 349 final Resources res = getResources(); 350 final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist); 351 352 // If duration < 0, this is a cue to compute the duration based on the distance 353 if (duration < 0) { 354 duration = res.getInteger(R.integer.config_dropAnimMaxDuration); 355 if (dist < maxDist) { 356 duration *= DEACCEL_1_5.getInterpolation(dist / maxDist); 357 } 358 duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration)); 359 } 360 361 // Fall back to cubic ease out interpolator for the animation if none is specified 362 TimeInterpolator interpolator = null; 363 if (alphaInterpolator == null || motionInterpolator == null) { 364 interpolator = DEACCEL_1_5; 365 } 366 367 // Animate the view 368 final float initAlpha = view.getAlpha(); 369 final float dropViewScale = view.getScaleX(); 370 AnimatorUpdateListener updateCb = new AnimatorUpdateListener() { 371 @Override 372 public void onAnimationUpdate(ValueAnimator animation) { 373 final float percent = (Float) animation.getAnimatedValue(); 374 final int width = view.getMeasuredWidth(); 375 final int height = view.getMeasuredHeight(); 376 377 float alphaPercent = alphaInterpolator == null ? percent : 378 alphaInterpolator.getInterpolation(percent); 379 float motionPercent = motionInterpolator == null ? percent : 380 motionInterpolator.getInterpolation(percent); 381 382 float initialScaleX = initScaleX * dropViewScale; 383 float initialScaleY = initScaleY * dropViewScale; 384 float scaleX = finalScaleX * percent + initialScaleX * (1 - percent); 385 float scaleY = finalScaleY * percent + initialScaleY * (1 - percent); 386 float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent); 387 388 float fromLeft = from.left + (initialScaleX - 1f) * width / 2; 389 float fromTop = from.top + (initialScaleY - 1f) * height / 2; 390 391 int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent))); 392 int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent))); 393 394 int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() * 395 (mAnchorViewInitialScrollX - mAnchorView.getScrollX())); 396 397 int xPos = x - mDropView.getScrollX() + anchorAdjust; 398 int yPos = y - mDropView.getScrollY(); 399 400 mDropView.setTranslationX(xPos); 401 mDropView.setTranslationY(yPos); 402 mDropView.setScaleX(scaleX); 403 mDropView.setScaleY(scaleY); 404 mDropView.setAlpha(alpha); 405 } 406 }; 407 animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle, 408 anchorView); 409 } 410 animateView(final DragView view, AnimatorUpdateListener updateCb, int duration, TimeInterpolator interpolator, final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView)411 public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration, 412 TimeInterpolator interpolator, final Runnable onCompleteRunnable, 413 final int animationEndStyle, View anchorView) { 414 // Clean up the previous animations 415 if (mDropAnim != null) mDropAnim.cancel(); 416 417 // Show the drop view if it was previously hidden 418 mDropView = view; 419 mDropView.cancelAnimation(); 420 mDropView.requestLayout(); 421 422 // Set the anchor view if the page is scrolling 423 if (anchorView != null) { 424 mAnchorViewInitialScrollX = anchorView.getScrollX(); 425 } 426 mAnchorView = anchorView; 427 428 // Create and start the animation 429 mDropAnim = new ValueAnimator(); 430 mDropAnim.setInterpolator(interpolator); 431 mDropAnim.setDuration(duration); 432 mDropAnim.setFloatValues(0f, 1f); 433 mDropAnim.addUpdateListener(updateCb); 434 mDropAnim.addListener(new AnimatorListenerAdapter() { 435 public void onAnimationEnd(Animator animation) { 436 if (onCompleteRunnable != null) { 437 onCompleteRunnable.run(); 438 } 439 switch (animationEndStyle) { 440 case ANIMATION_END_DISAPPEAR: 441 clearAnimatedView(); 442 break; 443 case ANIMATION_END_REMAIN_VISIBLE: 444 break; 445 } 446 mDropAnim = null; 447 } 448 }); 449 mDropAnim.start(); 450 } 451 clearAnimatedView()452 public void clearAnimatedView() { 453 if (mDropAnim != null) { 454 mDropAnim.cancel(); 455 } 456 mDropAnim = null; 457 if (mDropView != null) { 458 mDragController.onDeferredEndDrag(mDropView); 459 } 460 mDropView = null; 461 invalidate(); 462 } 463 getAnimatedView()464 public View getAnimatedView() { 465 return mDropView; 466 } 467 468 @Override onViewAdded(View child)469 public void onViewAdded(View child) { 470 super.onViewAdded(child); 471 updateChildIndices(); 472 mActivity.onDragLayerHierarchyChanged(); 473 } 474 475 @Override onViewRemoved(View child)476 public void onViewRemoved(View child) { 477 super.onViewRemoved(child); 478 updateChildIndices(); 479 mActivity.onDragLayerHierarchyChanged(); 480 } 481 482 @Override bringChildToFront(View child)483 public void bringChildToFront(View child) { 484 super.bringChildToFront(child); 485 updateChildIndices(); 486 } 487 updateChildIndices()488 private void updateChildIndices() { 489 mTopViewIndex = -1; 490 int childCount = getChildCount(); 491 for (int i = 0; i < childCount; i++) { 492 if (getChildAt(i) instanceof DragView) { 493 mTopViewIndex = i; 494 } 495 } 496 mChildCountOnLastUpdate = childCount; 497 } 498 499 @Override getChildDrawingOrder(int childCount, int i)500 protected int getChildDrawingOrder(int childCount, int i) { 501 if (mChildCountOnLastUpdate != childCount) { 502 // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed. 503 // Pre-18, the child was not added / removed by the time of those callbacks. We need to 504 // force update our representation of things here to avoid crashing on pre-18 devices 505 // in certain instances. 506 updateChildIndices(); 507 } 508 509 // i represents the current draw iteration 510 if (mTopViewIndex == -1) { 511 // in general we do nothing 512 return i; 513 } else if (i == childCount - 1) { 514 // if we have a top index, we return it when drawing last item (highest z-order) 515 return mTopViewIndex; 516 } else if (i < mTopViewIndex) { 517 return i; 518 } else { 519 // for indexes greater than the top index, we fetch one item above to shift for the 520 // displacement of the top index 521 return i + 1; 522 } 523 } 524 525 @Override dispatchDraw(Canvas canvas)526 protected void dispatchDraw(Canvas canvas) { 527 // Draw the background below children. 528 mWorkspaceScrim.draw(canvas); 529 mOverviewScrim.updateCurrentScrimmedView(this); 530 mFocusIndicatorHelper.draw(canvas); 531 super.dispatchDraw(canvas); 532 if (mOverviewScrim.getScrimmedView() == null) { 533 mOverviewScrim.draw(canvas); 534 } 535 } 536 537 @Override drawChild(Canvas canvas, View child, long drawingTime)538 protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 539 if (child == mOverviewScrim.getScrimmedView()) { 540 mOverviewScrim.draw(canvas); 541 } 542 return super.drawChild(canvas, child, drawingTime); 543 } 544 545 @Override onSizeChanged(int w, int h, int oldw, int oldh)546 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 547 super.onSizeChanged(w, h, oldw, oldh); 548 mWorkspaceScrim.setSize(w, h); 549 } 550 551 @Override setInsets(Rect insets)552 public void setInsets(Rect insets) { 553 super.setInsets(insets); 554 mWorkspaceScrim.onInsetsChanged(insets, mAllowSysuiScrims); 555 mOverviewScrim.onInsetsChanged(insets); 556 } 557 getScrim()558 public WorkspaceAndHotseatScrim getScrim() { 559 return mWorkspaceScrim; 560 } 561 getOverviewScrim()562 public OverviewScrim getOverviewScrim() { 563 return mOverviewScrim; 564 } 565 } 566