Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 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 package com.android.quickstep.util;
     17 
     18 import android.animation.Animator;
     19 import android.animation.AnimatorListenerAdapter;
     20 import android.animation.ValueAnimator;
     21 import android.graphics.Canvas;
     22 import android.graphics.ColorFilter;
     23 import android.graphics.PixelFormat;
     24 import android.graphics.drawable.Drawable;
     25 import android.util.FloatProperty;
     26 import android.view.View;
     27 
     28 import com.android.launcher3.Utilities;
     29 import com.android.quickstep.views.RecentsView;
     30 import com.android.quickstep.views.TaskThumbnailView;
     31 import com.android.quickstep.views.TaskView;
     32 
     33 public class TaskViewDrawable extends Drawable {
     34 
     35     public static final FloatProperty<TaskViewDrawable> PROGRESS =
     36             new FloatProperty<TaskViewDrawable>("progress") {
     37                 @Override
     38                 public void setValue(TaskViewDrawable taskViewDrawable, float v) {
     39                     taskViewDrawable.setProgress(v);
     40                 }
     41 
     42                 @Override
     43                 public Float get(TaskViewDrawable taskViewDrawable) {
     44                     return taskViewDrawable.mProgress;
     45                 }
     46             };
     47 
     48     /**
     49      * The progress at which we play the atomic icon scale animation.
     50      */
     51     private static final float ICON_SCALE_THRESHOLD = 0.95f;
     52 
     53     private final RecentsView mParent;
     54     private final View mIconView;
     55     private final int[] mIconPos;
     56 
     57     private final TaskThumbnailView mThumbnailView;
     58 
     59     private final ClipAnimationHelper mClipAnimationHelper;
     60 
     61     private float mProgress = 1;
     62     private boolean mPassedIconScaleThreshold;
     63     private ValueAnimator mIconScaleAnimator;
     64     private float mIconScale;
     65 
     66     public TaskViewDrawable(TaskView tv, RecentsView parent) {
     67         mParent = parent;
     68         mIconView = tv.getIconView();
     69         mIconPos = new int[2];
     70         mIconScale = mIconView.getScaleX();
     71         Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
     72 
     73         mThumbnailView = tv.getThumbnail();
     74         mClipAnimationHelper = new ClipAnimationHelper();
     75         mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView, parent);
     76     }
     77 
     78     public void setProgress(float progress) {
     79         mProgress = progress;
     80         mParent.invalidate();
     81         boolean passedIconScaleThreshold = progress <= ICON_SCALE_THRESHOLD;
     82         if (mPassedIconScaleThreshold != passedIconScaleThreshold) {
     83             mPassedIconScaleThreshold = passedIconScaleThreshold;
     84             animateIconScale(mPassedIconScaleThreshold ? 0 : 1);
     85         }
     86     }
     87 
     88     private void animateIconScale(float toScale) {
     89         if (mIconScaleAnimator != null) {
     90             mIconScaleAnimator.cancel();
     91         }
     92         mIconScaleAnimator = ValueAnimator.ofFloat(mIconScale, toScale);
     93         mIconScaleAnimator.addUpdateListener(valueAnimator -> {
     94             mIconScale = (float) valueAnimator.getAnimatedValue();
     95             if (mProgress > ICON_SCALE_THRESHOLD) {
     96                 // Speed up the icon scale to ensure it is 1 when progress is 1.
     97                 float iconProgress = (mProgress - ICON_SCALE_THRESHOLD) / (1 - ICON_SCALE_THRESHOLD);
     98                 if (iconProgress > mIconScale) {
     99                     mIconScale = iconProgress;
    100                 }
    101             }
    102             invalidateSelf();
    103         });
    104         mIconScaleAnimator.addListener(new AnimatorListenerAdapter() {
    105             @Override
    106             public void onAnimationEnd(Animator animation) {
    107                 mIconScaleAnimator = null;
    108             }
    109         });
    110         mIconScaleAnimator.setDuration(TaskView.SCALE_ICON_DURATION);
    111         mIconScaleAnimator.start();
    112     }
    113 
    114     @Override
    115     public void draw(Canvas canvas) {
    116         canvas.save();
    117         canvas.translate(mParent.getScrollX(), mParent.getScrollY());
    118         mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress);
    119         canvas.restore();
    120 
    121         canvas.save();
    122         canvas.translate(mIconPos[0], mIconPos[1]);
    123         canvas.scale(mIconScale, mIconScale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
    124         mIconView.draw(canvas);
    125         canvas.restore();
    126     }
    127 
    128     public ClipAnimationHelper getClipAnimationHelper() {
    129         return mClipAnimationHelper;
    130     }
    131 
    132     @Override
    133     public void setAlpha(int i) { }
    134 
    135     @Override
    136     public void setColorFilter(ColorFilter colorFilter) { }
    137 
    138     @Override
    139     public int getOpacity() {
    140         return PixelFormat.TRANSLUCENT;
    141     }
    142 }
    143