TaskView.java revision 231bc9c54a48921f9c6a1ae187969c9bfe9d121f
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.animation.Animator;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
22import android.animation.ValueAnimator;
23import android.content.Context;
24import android.content.res.Resources;
25import android.graphics.Color;
26import android.graphics.Outline;
27import android.graphics.Paint;
28import android.graphics.Point;
29import android.graphics.PorterDuff;
30import android.graphics.PorterDuffColorFilter;
31import android.graphics.Rect;
32import android.util.AttributeSet;
33import android.util.FloatProperty;
34import android.util.IntProperty;
35import android.util.Property;
36import android.view.MotionEvent;
37import android.view.View;
38import android.view.ViewDebug;
39import android.view.ViewOutlineProvider;
40import android.view.animation.AccelerateInterpolator;
41import android.widget.Toast;
42
43import com.android.internal.logging.MetricsLogger;
44import com.android.internal.logging.MetricsProto.MetricsEvent;
45import com.android.systemui.Interpolators;
46import com.android.systemui.R;
47import com.android.systemui.recents.Recents;
48import com.android.systemui.recents.RecentsActivity;
49import com.android.systemui.recents.RecentsConfiguration;
50import com.android.systemui.recents.events.EventBus;
51import com.android.systemui.recents.events.activity.LaunchTaskEvent;
52import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
53import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
54import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
55import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
56import com.android.systemui.recents.misc.ReferenceCountedTrigger;
57import com.android.systemui.recents.misc.SystemServicesProxy;
58import com.android.systemui.recents.misc.Utilities;
59import com.android.systemui.recents.model.Task;
60import com.android.systemui.recents.model.TaskStack;
61
62import java.util.ArrayList;
63
64import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
65
66/**
67 * A {@link TaskView} represents a fixed view of a task. Because the TaskView's layout is directed
68 * solely by the {@link TaskStackView}, we make it a fixed size layout which allows relayouts down
69 * the view hierarchy, but not upwards from any of its children (the TaskView will relayout itself
70 * with the previous bounds if any child requests layout).
71 */
72public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks,
73        TaskStackAnimationHelper.Callbacks, View.OnClickListener, View.OnLongClickListener {
74
75    /** The TaskView callbacks */
76    interface TaskViewCallbacks {
77        void onTaskViewClipStateChanged(TaskView tv);
78    }
79
80    /**
81     * The dim overlay is generally calculated from the task progress, but occasionally (like when
82     * launching) needs to be animated independently of the task progress.
83     */
84    public static final Property<TaskView, Integer> DIM =
85            new IntProperty<TaskView>("dim") {
86                @Override
87                public void setValue(TaskView tv, int dim) {
88                    tv.setDim(dim);
89                }
90
91                @Override
92                public Integer get(TaskView tv) {
93                    return tv.getDim();
94                }
95            };
96
97    public static final Property<TaskView, Float> TASK_PROGRESS =
98            new FloatProperty<TaskView>("taskProgress") {
99                @Override
100                public void setValue(TaskView tv, float p) {
101                    tv.setTaskProgress(p);
102                }
103
104                @Override
105                public Float get(TaskView tv) {
106                    return tv.getTaskProgress();
107                }
108            };
109
110    @ViewDebug.ExportedProperty(category="recents")
111    float mTaskProgress;
112    @ViewDebug.ExportedProperty(category="recents")
113    float mMaxDimScale;
114    @ViewDebug.ExportedProperty(category="recents")
115    int mDimAlpha;
116    AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
117    PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
118    Paint mDimLayerPaint = new Paint();
119    float mActionButtonTranslationZ;
120
121    @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
122    Task mTask;
123    @ViewDebug.ExportedProperty(category="recents")
124    boolean mTaskDataLoaded;
125    @ViewDebug.ExportedProperty(category="recents")
126    boolean mClipViewInStack = true;
127    @ViewDebug.ExportedProperty(category="recents")
128    boolean mTouchExplorationEnabled;
129    @ViewDebug.ExportedProperty(category="recents")
130    boolean mIsDisabledInSafeMode;
131    @ViewDebug.ExportedProperty(deepExport=true, prefix="view_bounds_")
132    AnimateableViewBounds mViewBounds;
133
134    private AnimatorSet mTransformAnimation;
135    private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
136
137    View mContent;
138    @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
139    TaskViewThumbnail mThumbnailView;
140    @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
141    TaskViewHeader mHeaderView;
142    View mActionButtonView;
143    TaskViewCallbacks mCb;
144
145    @ViewDebug.ExportedProperty(category="recents")
146    Point mDownTouchPos = new Point();
147
148    private Toast mDisabledAppToast;
149
150    public TaskView(Context context) {
151        this(context, null);
152    }
153
154    public TaskView(Context context, AttributeSet attrs) {
155        this(context, attrs, 0);
156    }
157
158    public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
159        this(context, attrs, defStyleAttr, 0);
160    }
161
162    public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
163        super(context, attrs, defStyleAttr, defStyleRes);
164        RecentsConfiguration config = Recents.getConfiguration();
165        Resources res = context.getResources();
166        mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
167        mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
168                R.dimen.recents_task_view_rounded_corners_radius));
169        if (config.fakeShadows) {
170            setBackground(new FakeShadowDrawable(res, config));
171        }
172        setOutlineProvider(mViewBounds);
173        setOnLongClickListener(this);
174    }
175
176    /** Set callback */
177    void setCallbacks(TaskViewCallbacks cb) {
178        mCb = cb;
179    }
180
181    /** Resets this TaskView for reuse. */
182    void reset() {
183        resetViewProperties();
184        resetNoUserInteractionState();
185        readSystemFlags();
186        setClipViewInStack(false);
187        setCallbacks(null);
188    }
189
190    /** Gets the task */
191    public Task getTask() {
192        return mTask;
193    }
194
195    /** Returns the view bounds. */
196    AnimateableViewBounds getViewBounds() {
197        return mViewBounds;
198    }
199
200    @Override
201    protected void onAttachedToWindow() {
202        super.onAttachedToWindow();
203        readSystemFlags();
204    }
205
206    @Override
207    protected void onFinishInflate() {
208        // Bind the views
209        mContent = findViewById(R.id.task_view_content);
210        mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
211        mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
212        mActionButtonView = findViewById(R.id.lock_to_app_fab);
213        mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
214            @Override
215            public void getOutline(View view, Outline outline) {
216                // Set the outline to match the FAB background
217                outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
218                outline.setAlpha(0.35f);
219            }
220        });
221        mActionButtonView.setOnClickListener(this);
222        mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
223    }
224
225    @Override
226    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
227        super.onSizeChanged(w, h, oldw, oldh);
228        if (w > 0 && h > 0) {
229            mHeaderView.onTaskViewSizeChanged(w, h);
230            mThumbnailView.onTaskViewSizeChanged(w, h);
231        }
232    }
233
234    @Override
235    public boolean hasOverlappingRendering() {
236        return false;
237    }
238
239    @Override
240    public boolean onInterceptTouchEvent(MotionEvent ev) {
241        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
242            mDownTouchPos.set((int) (ev.getX() * getScaleX()), (int) (ev.getY() * getScaleY()));
243        }
244        return super.onInterceptTouchEvent(ev);
245    }
246
247
248    @Override
249    protected void measureContents(int width, int height) {
250        int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
251        int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
252
253        // Measure the content
254        mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
255                MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
256
257        // Optimization: Prevent overdraw of the thumbnail under the header view
258        mThumbnailView.updateClipToTaskBar(mHeaderView);
259
260        setMeasuredDimension(width, height);
261    }
262
263    void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform,
264            AnimationProps toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) {
265        RecentsConfiguration config = Recents.getConfiguration();
266        cancelTransformAnimation();
267
268        // Compose the animations for the transform
269        mTmpAnimators.clear();
270        toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, !config.fakeShadows);
271        if (toAnimation.isImmediate()) {
272            if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
273                setTaskProgress(toTransform.p);
274            }
275            // Manually call back to the animator listener and update callback
276            if (toAnimation.getListener() != null) {
277                toAnimation.getListener().onAnimationEnd(null);
278            }
279            if (updateCallback != null) {
280                updateCallback.onAnimationUpdate(null);
281            }
282        } else {
283            // Both the progress and the update are a function of the bounds movement of the task
284            if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
285                ObjectAnimator anim = ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
286                        toTransform.p);
287                mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim));
288            }
289            if (updateCallback != null) {
290                ValueAnimator updateCallbackAnim = ValueAnimator.ofInt(0, 1);
291                updateCallbackAnim.addUpdateListener(updateCallback);
292                mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, updateCallbackAnim));
293            }
294
295            // Create the animator
296            mTransformAnimation = toAnimation.createAnimator(mTmpAnimators);
297            mTransformAnimation.start();
298        }
299    }
300
301    /** Resets this view's properties */
302    void resetViewProperties() {
303        cancelTransformAnimation();
304        setDim(0);
305        setVisibility(View.VISIBLE);
306        getViewBounds().reset();
307        getHeaderView().reset();
308        TaskViewTransform.reset(this);
309
310        mActionButtonView.setScaleX(1f);
311        mActionButtonView.setScaleY(1f);
312        mActionButtonView.setAlpha(0f);
313        mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
314    }
315
316    /**
317     * Cancels any current transform animations.
318     */
319    public void cancelTransformAnimation() {
320        Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation);
321    }
322
323    /** Enables/disables handling touch on this task view. */
324    void setTouchEnabled(boolean enabled) {
325        setOnClickListener(enabled ? this : null);
326    }
327
328    /** Animates this task view if the user does not interact with the stack after a certain time. */
329    void startNoUserInteractionAnimation() {
330        mHeaderView.startNoUserInteractionAnimation();
331    }
332
333    /** Mark this task view that the user does has not interacted with the stack after a certain time. */
334    void setNoUserInteractionState() {
335        mHeaderView.setNoUserInteractionState();
336    }
337
338    /** Resets the state tracking that the user has not interacted with the stack after a certain time. */
339    void resetNoUserInteractionState() {
340        mHeaderView.resetNoUserInteractionState();
341    }
342
343    /** Dismisses this task. */
344    void dismissTask() {
345        // Animate out the view and call the callback
346        final TaskView tv = this;
347        DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv, mTask);
348        dismissEvent.addPostAnimationCallback(new Runnable() {
349            @Override
350            public void run() {
351                EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv));
352            }
353        });
354        EventBus.getDefault().send(dismissEvent);
355    }
356
357    /**
358     * Returns whether this view should be clipped, or any views below should clip against this
359     * view.
360     */
361    boolean shouldClipViewInStack() {
362        // Never clip for freeform tasks or if invisible
363        if (mTask.isFreeformTask() || getVisibility() != View.VISIBLE) {
364            return false;
365        }
366        return mClipViewInStack;
367    }
368
369    /** Sets whether this view should be clipped, or clipped against. */
370    void setClipViewInStack(boolean clip) {
371        if (clip != mClipViewInStack) {
372            mClipViewInStack = clip;
373            if (mCb != null) {
374                mCb.onTaskViewClipStateChanged(this);
375            }
376        }
377    }
378
379    /** Sets the current task progress. */
380    public void setTaskProgress(float p) {
381        mTaskProgress = p;
382        mViewBounds.setAlpha(p);
383        updateDimFromTaskProgress();
384    }
385
386    public TaskViewHeader getHeaderView() {
387        return mHeaderView;
388    }
389
390    /** Returns the current task progress. */
391    public float getTaskProgress() {
392        return mTaskProgress;
393    }
394
395    /** Returns the current dim. */
396    public void setDim(int dim) {
397        RecentsConfiguration config = Recents.getConfiguration();
398
399        mDimAlpha = dim;
400        if (config.useHardwareLayers) {
401            // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
402            if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
403                mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
404                mDimLayerPaint.setColorFilter(mDimColorFilter);
405                mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
406            }
407        } else {
408            float dimAlpha = mDimAlpha / 255.0f;
409            mThumbnailView.setDimAlpha(dimAlpha);
410            mHeaderView.setDimAlpha(dimAlpha);
411        }
412    }
413
414    /** Returns the current dim. */
415    public int getDim() {
416        return mDimAlpha;
417    }
418
419    /** Animates the dim to the task progress. */
420    void animateDimToProgress(int duration, Animator.AnimatorListener animListener) {
421        // Animate the dim into view as well
422        int toDim = getDimFromTaskProgress();
423        if (toDim != getDim()) {
424            ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), toDim);
425            anim.setDuration(duration);
426            if (animListener != null) {
427                anim.addListener(animListener);
428            }
429            anim.start();
430        } else {
431            animListener.onAnimationEnd(null);
432        }
433    }
434
435    /** Compute the dim as a function of the scale of this view. */
436    int getDimFromTaskProgress() {
437        float x = mTaskProgress < 0
438                ? 1f
439                : mDimInterpolator.getInterpolation(1f - mTaskProgress);
440        float dim = mMaxDimScale * x;
441        return (int) (dim * 255);
442    }
443
444    /** Update the dim as a function of the scale of this view. */
445    void updateDimFromTaskProgress() {
446        setDim(getDimFromTaskProgress());
447    }
448
449    /**
450     * Explicitly sets the focused state of this task.
451     */
452    public void setFocusedState(boolean isFocused, boolean requestViewFocus) {
453        SystemServicesProxy ssp = Recents.getSystemServices();
454        if (isFocused) {
455            if (requestViewFocus && !isFocused()) {
456                requestFocus();
457            }
458            if (requestViewFocus && !isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
459                requestAccessibilityFocus();
460            }
461        } else {
462            if (isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
463                clearAccessibilityFocus();
464            }
465        }
466    }
467
468    /**
469     * Shows the action button.
470     * @param fadeIn whether or not to animate the action button in.
471     * @param fadeInDuration the duration of the action button animation, only used if
472     *                       {@param fadeIn} is true.
473     */
474    public void showActionButton(boolean fadeIn, int fadeInDuration) {
475        mActionButtonView.setVisibility(View.VISIBLE);
476
477        if (fadeIn && mActionButtonView.getAlpha() < 1f) {
478            mActionButtonView.animate()
479                    .alpha(1f)
480                    .scaleX(1f)
481                    .scaleY(1f)
482                    .setDuration(fadeInDuration)
483                    .setInterpolator(Interpolators.ALPHA_IN)
484                    .start();
485        } else {
486            mActionButtonView.setScaleX(1f);
487            mActionButtonView.setScaleY(1f);
488            mActionButtonView.setAlpha(1f);
489            mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
490        }
491    }
492
493    /**
494     * Immediately hides the action button.
495     *
496     * @param fadeOut whether or not to animate the action button out.
497     */
498    public void hideActionButton(boolean fadeOut, int fadeOutDuration, boolean scaleDown,
499            final Animator.AnimatorListener animListener) {
500        if (fadeOut && mActionButtonView.getAlpha() > 0f) {
501            if (scaleDown) {
502                float toScale = 0.9f;
503                mActionButtonView.animate()
504                        .scaleX(toScale)
505                        .scaleY(toScale);
506            }
507            mActionButtonView.animate()
508                    .alpha(0f)
509                    .setDuration(fadeOutDuration)
510                    .setInterpolator(Interpolators.ALPHA_OUT)
511                    .withEndAction(new Runnable() {
512                        @Override
513                        public void run() {
514                            if (animListener != null) {
515                                animListener.onAnimationEnd(null);
516                            }
517                            mActionButtonView.setVisibility(View.INVISIBLE);
518                        }
519                    })
520                    .start();
521        } else {
522            mActionButtonView.setAlpha(0f);
523            mActionButtonView.setVisibility(View.INVISIBLE);
524            if (animListener != null) {
525                animListener.onAnimationEnd(null);
526            }
527        }
528    }
529
530    /**** TaskStackAnimationHelper.Callbacks Implementation ****/
531
532    @Override
533    public void onPrepareLaunchTargetForEnterAnimation() {
534        // These values will be animated in when onStartLaunchTargetEnterAnimation() is called
535        setDim(0);
536        mActionButtonView.setAlpha(0f);
537    }
538
539    @Override
540    public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
541            ReferenceCountedTrigger postAnimationTrigger) {
542        postAnimationTrigger.increment();
543        animateDimToProgress(duration, postAnimationTrigger.decrementOnAnimationEnd());
544
545        if (screenPinningEnabled) {
546            showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
547        }
548    }
549
550    @Override
551    public void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
552            ReferenceCountedTrigger postAnimationTrigger) {
553        if (mDimAlpha > 0) {
554            ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
555            anim.setDuration(duration);
556            anim.setInterpolator(Interpolators.ALPHA_OUT);
557            anim.start();
558        }
559
560        postAnimationTrigger.increment();
561        hideActionButton(true /* fadeOut */, duration,
562                !screenPinningRequested /* scaleDown */,
563                postAnimationTrigger.decrementOnAnimationEnd());
564    }
565
566    /**** TaskCallbacks Implementation ****/
567
568    public void onTaskBound(Task t) {
569        SystemServicesProxy ssp = Recents.getSystemServices();
570        mTask = t;
571        mTask.addCallback(this);
572        mIsDisabledInSafeMode = !mTask.isSystemApp && ssp.isInSafeMode();
573    }
574
575    @Override
576    public void onTaskDataLoaded(Task task) {
577        // Bind each of the views to the new task data
578        mThumbnailView.rebindToTask(mTask, mIsDisabledInSafeMode);
579        mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
580        mTaskDataLoaded = true;
581    }
582
583    @Override
584    public void onTaskDataUnloaded() {
585        // Unbind each of the views from the task data and remove the task callback
586        mTask.removeCallback(this);
587        mThumbnailView.unbindFromTask();
588        mHeaderView.unbindFromTask(mTouchExplorationEnabled);
589        mTaskDataLoaded = false;
590    }
591
592    @Override
593    public void onTaskStackIdChanged() {
594        mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
595    }
596
597    /**** View.OnClickListener Implementation ****/
598
599    @Override
600     public void onClick(final View v) {
601        if (mIsDisabledInSafeMode) {
602            Context context = getContext();
603            String msg = context.getString(R.string.recents_launch_disabled_message, mTask.title);
604            if (mDisabledAppToast != null) {
605                mDisabledAppToast.cancel();
606            }
607            mDisabledAppToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
608            mDisabledAppToast.show();
609            return;
610        }
611
612        boolean screenPinningRequested = false;
613        if (v == mActionButtonView) {
614            // Reset the translation of the action button before we animate it out
615            mActionButtonView.setTranslationZ(0f);
616            screenPinningRequested = true;
617        }
618        EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
619                screenPinningRequested));
620
621        MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
622                mTask.key.getComponent().toString());
623    }
624
625    /**** View.OnLongClickListener Implementation ****/
626
627    @Override
628    public boolean onLongClick(View v) {
629        SystemServicesProxy ssp = Recents.getSystemServices();
630        // Since we are clipping the view to the bounds, manually do the hit test
631        Rect clipBounds = new Rect(mViewBounds.mClipBounds);
632        clipBounds.scale(getScaleX());
633        boolean inBounds = clipBounds.contains(mDownTouchPos.x, mDownTouchPos.y);
634        if (v == this && inBounds && !ssp.hasDockedTask()) {
635            // Start listening for drag events
636            setClipViewInStack(false);
637
638            mDownTouchPos.x += ((1f - getScaleX()) * getWidth()) / 2;
639            mDownTouchPos.y += ((1f - getScaleY()) * getHeight()) / 2;
640
641            EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
642            EventBus.getDefault().send(new DragStartEvent(mTask, this, mDownTouchPos));
643            return true;
644        }
645        return false;
646    }
647
648    /**** Events ****/
649
650    public final void onBusEvent(DragEndEvent event) {
651        if (!(event.dropTarget instanceof TaskStack.DockState)) {
652            event.addPostAnimationCallback(new Runnable() {
653                @Override
654                public void run() {
655                    // Animate the drag view back from where it is, to the view location, then after
656                    // it returns, update the clip state
657                    setClipViewInStack(true);
658                }
659            });
660        }
661        EventBus.getDefault().unregister(this);
662    }
663
664    /**
665     * Reads current system flags related to accessibility and screen pinning.
666     */
667    private void readSystemFlags() {
668        SystemServicesProxy ssp = Recents.getSystemServices();
669        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
670    }
671}
672