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 17 package com.android.systemui.recents.views; 18 19 import android.animation.ObjectAnimator; 20 import android.animation.ValueAnimator; 21 import android.graphics.Outline; 22 import android.graphics.Rect; 23 import android.view.View; 24 import android.view.ViewOutlineProvider; 25 26 import com.android.systemui.recents.RecentsConfiguration; 27 28 /* An outline provider that has a clip and outline that can be animated. */ 29 public class AnimateableViewBounds extends ViewOutlineProvider { 30 31 RecentsConfiguration mConfig; 32 33 TaskView mSourceView; 34 Rect mTmpRect = new Rect(); 35 Rect mClipRect = new Rect(); 36 Rect mClipBounds = new Rect(); 37 Rect mOutlineClipRect = new Rect(); 38 int mCornerRadius; 39 float mAlpha = 1f; 40 final float mMinAlpha = 0.25f; 41 42 ObjectAnimator mClipTopAnimator; 43 ObjectAnimator mClipRightAnimator; 44 ObjectAnimator mClipBottomAnimator; 45 AnimateableViewBounds(TaskView source, int cornerRadius)46 public AnimateableViewBounds(TaskView source, int cornerRadius) { 47 mConfig = RecentsConfiguration.getInstance(); 48 mSourceView = source; 49 mCornerRadius = cornerRadius; 50 setClipTop(getClipTop()); 51 setClipRight(getClipRight()); 52 setClipBottom(getClipBottom()); 53 setOutlineClipBottom(getOutlineClipBottom()); 54 } 55 56 @Override getOutline(View view, Outline outline)57 public void getOutline(View view, Outline outline) { 58 outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha)); 59 outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left), 60 Math.max(mClipRect.top, mOutlineClipRect.top), 61 mSourceView.getWidth() - Math.max(mClipRect.right, mOutlineClipRect.right), 62 mSourceView.getHeight() - Math.max(mClipRect.bottom, mOutlineClipRect.bottom), 63 mCornerRadius); 64 } 65 66 /** Sets the view outline alpha. */ setAlpha(float alpha)67 void setAlpha(float alpha) { 68 if (Float.compare(alpha, mAlpha) != 0) { 69 mAlpha = alpha; 70 mSourceView.invalidateOutline(); 71 } 72 } 73 74 /** Animates the top clip. */ animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener)75 void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) { 76 if (mClipTopAnimator != null) { 77 mClipTopAnimator.removeAllListeners(); 78 mClipTopAnimator.cancel(); 79 } 80 mClipTopAnimator = ObjectAnimator.ofInt(this, "clipTop", top); 81 mClipTopAnimator.setDuration(duration); 82 mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); 83 if (updateListener != null) { 84 mClipTopAnimator.addUpdateListener(updateListener); 85 } 86 mClipTopAnimator.start(); 87 } 88 89 /** Sets the top clip. */ setClipTop(int top)90 public void setClipTop(int top) { 91 if (top != mClipRect.top) { 92 mClipRect.top = top; 93 mSourceView.invalidateOutline(); 94 updateClipBounds(); 95 } 96 } 97 98 /** Returns the top clip. */ getClipTop()99 public int getClipTop() { 100 return mClipRect.top; 101 } 102 103 /** Animates the right clip. */ animateClipRight(int right, int duration)104 void animateClipRight(int right, int duration) { 105 if (mClipRightAnimator != null) { 106 mClipRightAnimator.removeAllListeners(); 107 mClipRightAnimator.cancel(); 108 } 109 mClipRightAnimator = ObjectAnimator.ofInt(this, "clipRight", right); 110 mClipRightAnimator.setDuration(duration); 111 mClipRightAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); 112 mClipRightAnimator.start(); 113 } 114 115 /** Sets the right clip. */ setClipRight(int right)116 public void setClipRight(int right) { 117 if (right != mClipRect.right) { 118 mClipRect.right = right; 119 mSourceView.invalidateOutline(); 120 updateClipBounds(); 121 } 122 } 123 124 /** Returns the right clip. */ getClipRight()125 public int getClipRight() { 126 return mClipRect.right; 127 } 128 129 /** Animates the bottom clip. */ animateClipBottom(int bottom, int duration)130 void animateClipBottom(int bottom, int duration) { 131 if (mClipBottomAnimator != null) { 132 mClipBottomAnimator.removeAllListeners(); 133 mClipBottomAnimator.cancel(); 134 } 135 mClipBottomAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom); 136 mClipBottomAnimator.setDuration(duration); 137 mClipBottomAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); 138 mClipBottomAnimator.start(); 139 } 140 141 /** Sets the bottom clip. */ setClipBottom(int bottom)142 public void setClipBottom(int bottom) { 143 if (bottom != mClipRect.bottom) { 144 mClipRect.bottom = bottom; 145 mSourceView.invalidateOutline(); 146 updateClipBounds(); 147 if (!mConfig.useHardwareLayers) { 148 mSourceView.mThumbnailView.updateVisibility( 149 bottom - mSourceView.getPaddingBottom()); 150 } 151 } 152 } 153 154 /** Returns the bottom clip. */ getClipBottom()155 public int getClipBottom() { 156 return mClipRect.bottom; 157 } 158 159 /** Sets the outline bottom clip. */ setOutlineClipBottom(int bottom)160 public void setOutlineClipBottom(int bottom) { 161 if (bottom != mOutlineClipRect.bottom) { 162 mOutlineClipRect.bottom = bottom; 163 mSourceView.invalidateOutline(); 164 } 165 } 166 167 /** Gets the outline bottom clip. */ getOutlineClipBottom()168 public int getOutlineClipBottom() { 169 return mOutlineClipRect.bottom; 170 } 171 updateClipBounds()172 private void updateClipBounds() { 173 mClipBounds.set(mClipRect.left, mClipRect.top, 174 mSourceView.getWidth() - mClipRect.right, 175 mSourceView.getHeight() - mClipRect.bottom); 176 mSourceView.setClipBounds(mClipBounds); 177 } 178 } 179