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