17d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal/*
27d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * Copyright (C) 2018 The Android Open Source Project
37d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal *
47d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * Licensed under the Apache License, Version 2.0 (the "License");
57d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * you may not use this file except in compliance with the License.
67d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * You may obtain a copy of the License at
77d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal *
87d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal *      http://www.apache.org/licenses/LICENSE-2.0
97d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal *
107d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * Unless required by applicable law or agreed to in writing, software
117d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * distributed under the License is distributed on an "AS IS" BASIS,
127d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * See the License for the specific language governing permissions and
147d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal * limitations under the License.
157d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal */
167d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalpackage com.android.quickstep.util;
177d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
18b271ad89728d9af582022a07fd190c3f3d685b97Tonyimport android.animation.Animator;
19b271ad89728d9af582022a07fd190c3f3d685b97Tonyimport android.animation.AnimatorListenerAdapter;
20b271ad89728d9af582022a07fd190c3f3d685b97Tonyimport android.animation.ValueAnimator;
217d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport android.graphics.Canvas;
227d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport android.graphics.ColorFilter;
237d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport android.graphics.PixelFormat;
247d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport android.graphics.drawable.Drawable;
257d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport android.util.FloatProperty;
2685c53f2af562f0b4a2ec50d1bf83bbaf64fd57ebSunny Goyalimport android.view.View;
277d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
287d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport com.android.launcher3.Utilities;
297d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport com.android.quickstep.views.RecentsView;
307d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport com.android.quickstep.views.TaskThumbnailView;
317d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalimport com.android.quickstep.views.TaskView;
327d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
337d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyalpublic class TaskViewDrawable extends Drawable {
347d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
35b271ad89728d9af582022a07fd190c3f3d685b97Tony    public static final FloatProperty<TaskViewDrawable> PROGRESS =
367d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal            new FloatProperty<TaskViewDrawable>("progress") {
377d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                @Override
387d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                public void setValue(TaskViewDrawable taskViewDrawable, float v) {
397d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                    taskViewDrawable.setProgress(v);
407d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                }
417d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
427d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                @Override
437d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                public Float get(TaskViewDrawable taskViewDrawable) {
447d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                    return taskViewDrawable.mProgress;
457d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal                }
467d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal            };
477d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
48b271ad89728d9af582022a07fd190c3f3d685b97Tony    /**
49b271ad89728d9af582022a07fd190c3f3d685b97Tony     * The progress at which we play the atomic icon scale animation.
50b271ad89728d9af582022a07fd190c3f3d685b97Tony     */
51b271ad89728d9af582022a07fd190c3f3d685b97Tony    private static final float ICON_SCALE_THRESHOLD = 0.95f;
527d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
537d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    private final RecentsView mParent;
5485c53f2af562f0b4a2ec50d1bf83bbaf64fd57ebSunny Goyal    private final View mIconView;
557d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    private final int[] mIconPos;
567d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
577d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    private final TaskThumbnailView mThumbnailView;
587d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
597d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    private final ClipAnimationHelper mClipAnimationHelper;
607d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
617d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    private float mProgress = 1;
62b271ad89728d9af582022a07fd190c3f3d685b97Tony    private boolean mPassedIconScaleThreshold;
63b271ad89728d9af582022a07fd190c3f3d685b97Tony    private ValueAnimator mIconScaleAnimator;
64b271ad89728d9af582022a07fd190c3f3d685b97Tony    private float mIconScale;
657d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
667d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    public TaskViewDrawable(TaskView tv, RecentsView parent) {
677d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mParent = parent;
687d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mIconView = tv.getIconView();
697d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mIconPos = new int[2];
70b271ad89728d9af582022a07fd190c3f3d685b97Tony        mIconScale = mIconView.getScaleX();
717d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
727d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
737d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mThumbnailView = tv.getThumbnail();
747d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mClipAnimationHelper = new ClipAnimationHelper();
75f3d7328518201927e364c7a7529e311a4bb00607Sunny Goyal        mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView, parent);
767d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    }
777d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
787d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    public void setProgress(float progress) {
797d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mProgress = progress;
807d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mParent.invalidate();
81b271ad89728d9af582022a07fd190c3f3d685b97Tony        boolean passedIconScaleThreshold = progress <= ICON_SCALE_THRESHOLD;
82b271ad89728d9af582022a07fd190c3f3d685b97Tony        if (mPassedIconScaleThreshold != passedIconScaleThreshold) {
83b271ad89728d9af582022a07fd190c3f3d685b97Tony            mPassedIconScaleThreshold = passedIconScaleThreshold;
84b271ad89728d9af582022a07fd190c3f3d685b97Tony            animateIconScale(mPassedIconScaleThreshold ? 0 : 1);
85b271ad89728d9af582022a07fd190c3f3d685b97Tony        }
86b271ad89728d9af582022a07fd190c3f3d685b97Tony    }
87b271ad89728d9af582022a07fd190c3f3d685b97Tony
88b271ad89728d9af582022a07fd190c3f3d685b97Tony    private void animateIconScale(float toScale) {
89b271ad89728d9af582022a07fd190c3f3d685b97Tony        if (mIconScaleAnimator != null) {
90b271ad89728d9af582022a07fd190c3f3d685b97Tony            mIconScaleAnimator.cancel();
91b271ad89728d9af582022a07fd190c3f3d685b97Tony        }
92b271ad89728d9af582022a07fd190c3f3d685b97Tony        mIconScaleAnimator = ValueAnimator.ofFloat(mIconScale, toScale);
93b271ad89728d9af582022a07fd190c3f3d685b97Tony        mIconScaleAnimator.addUpdateListener(valueAnimator -> {
94b271ad89728d9af582022a07fd190c3f3d685b97Tony            mIconScale = (float) valueAnimator.getAnimatedValue();
95b271ad89728d9af582022a07fd190c3f3d685b97Tony            if (mProgress > ICON_SCALE_THRESHOLD) {
96b271ad89728d9af582022a07fd190c3f3d685b97Tony                // Speed up the icon scale to ensure it is 1 when progress is 1.
97b271ad89728d9af582022a07fd190c3f3d685b97Tony                float iconProgress = (mProgress - ICON_SCALE_THRESHOLD) / (1 - ICON_SCALE_THRESHOLD);
98b271ad89728d9af582022a07fd190c3f3d685b97Tony                if (iconProgress > mIconScale) {
99b271ad89728d9af582022a07fd190c3f3d685b97Tony                    mIconScale = iconProgress;
100b271ad89728d9af582022a07fd190c3f3d685b97Tony                }
101b271ad89728d9af582022a07fd190c3f3d685b97Tony            }
102b271ad89728d9af582022a07fd190c3f3d685b97Tony            invalidateSelf();
103b271ad89728d9af582022a07fd190c3f3d685b97Tony        });
104b271ad89728d9af582022a07fd190c3f3d685b97Tony        mIconScaleAnimator.addListener(new AnimatorListenerAdapter() {
105b271ad89728d9af582022a07fd190c3f3d685b97Tony            @Override
106b271ad89728d9af582022a07fd190c3f3d685b97Tony            public void onAnimationEnd(Animator animation) {
107b271ad89728d9af582022a07fd190c3f3d685b97Tony                mIconScaleAnimator = null;
108b271ad89728d9af582022a07fd190c3f3d685b97Tony            }
109b271ad89728d9af582022a07fd190c3f3d685b97Tony        });
110b271ad89728d9af582022a07fd190c3f3d685b97Tony        mIconScaleAnimator.setDuration(TaskView.SCALE_ICON_DURATION);
111b271ad89728d9af582022a07fd190c3f3d685b97Tony        mIconScaleAnimator.start();
1127d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    }
1137d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
1147d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    @Override
1157d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    public void draw(Canvas canvas) {
1167d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        canvas.save();
1177d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        canvas.translate(mParent.getScrollX(), mParent.getScrollY());
1187d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress);
1197d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        canvas.restore();
1207d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
1217d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        canvas.save();
1227d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        canvas.translate(mIconPos[0], mIconPos[1]);
123b271ad89728d9af582022a07fd190c3f3d685b97Tony        canvas.scale(mIconScale, mIconScale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
1247d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        mIconView.draw(canvas);
1257d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        canvas.restore();
1267d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    }
1277d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
1285fdd300e8a6481502bb3728fea500270d6d4722aSunny Goyal    public ClipAnimationHelper getClipAnimationHelper() {
1295fdd300e8a6481502bb3728fea500270d6d4722aSunny Goyal        return mClipAnimationHelper;
1305fdd300e8a6481502bb3728fea500270d6d4722aSunny Goyal    }
1315fdd300e8a6481502bb3728fea500270d6d4722aSunny Goyal
1327d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    @Override
1337d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    public void setAlpha(int i) { }
1347d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
1357d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    @Override
1367d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    public void setColorFilter(ColorFilter colorFilter) { }
1377d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal
1387d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    @Override
1397d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    public int getOpacity() {
1407d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal        return PixelFormat.TRANSLUCENT;
1417d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal    }
1427d2e40912eb7007e8378f106556b4cbcbc24d661Sunny Goyal}
143