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