TaskView.java revision 2f2ca08baa072376b3dfd60506625496aa05903f
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.content.Context; 23import android.graphics.Bitmap; 24import android.graphics.Canvas; 25import android.graphics.Color; 26import android.graphics.Path; 27import android.graphics.Rect; 28import android.graphics.RectF; 29import android.util.AttributeSet; 30import android.view.View; 31import android.widget.FrameLayout; 32import com.android.systemui.R; 33import com.android.systemui.recents.BakedBezierInterpolator; 34import com.android.systemui.recents.Constants; 35import com.android.systemui.recents.RecentsConfiguration; 36import com.android.systemui.recents.Utilities; 37import com.android.systemui.recents.model.Task; 38 39import java.util.Random; 40 41 42/* A task view */ 43public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks { 44 /** The TaskView callbacks */ 45 interface TaskViewCallbacks { 46 public void onTaskIconClicked(TaskView tv); 47 // public void onTaskViewReboundToTask(TaskView tv, Task t); 48 } 49 50 Task mTask; 51 boolean mTaskDataLoaded; 52 53 TaskThumbnailView mThumbnailView; 54 TaskBarView mBarView; 55 TaskViewCallbacks mCb; 56 57 Path mRoundedRectClipPath = new Path(); 58 59 60 public TaskView(Context context) { 61 this(context, null); 62 } 63 64 public TaskView(Context context, AttributeSet attrs) { 65 this(context, attrs, 0); 66 } 67 68 public TaskView(Context context, AttributeSet attrs, int defStyleAttr) { 69 this(context, attrs, defStyleAttr, 0); 70 } 71 72 public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 73 super(context, attrs, defStyleAttr, defStyleRes); 74 setWillNotDraw(false); 75 } 76 77 @Override 78 protected void onFinishInflate() { 79 // Bind the views 80 mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail); 81 mBarView = (TaskBarView) findViewById(R.id.task_view_bar); 82 mBarView.mApplicationIcon.setOnClickListener(this); 83 if (mTaskDataLoaded) { 84 onTaskDataLoaded(false); 85 } 86 } 87 88 @Override 89 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 90 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 91 92 // Update the rounded rect clip path 93 RecentsConfiguration config = RecentsConfiguration.getInstance(); 94 float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps); 95 mRoundedRectClipPath.reset(); 96 mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()), 97 radius, radius, Path.Direction.CW); 98 } 99 100 @Override 101 protected void dispatchDraw(Canvas canvas) { 102 int restoreCount = 0; 103 if (Constants.Values.TaskView.UseRoundedCorners) { 104 restoreCount = canvas.save(); 105 canvas.clipPath(mRoundedRectClipPath); 106 } 107 super.dispatchDraw(canvas); 108 if (Constants.Values.TaskView.UseRoundedCorners) { 109 canvas.restoreToCount(restoreCount); 110 } 111 } 112 113 /** Set callback */ 114 void setCallbacks(TaskViewCallbacks cb) { 115 mCb = cb; 116 } 117 118 /** Gets the task */ 119 Task getTask() { 120 return mTask; 121 } 122 123 /** Synchronizes this view's properties with the task's transform */ 124 void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform, 125 TaskViewTransform toTransform, int duration) { 126 if (duration > 0) { 127 if (animateFromTransform != null) { 128 setTranslationY(animateFromTransform.translationY); 129 setScaleX(animateFromTransform.scale); 130 setScaleY(animateFromTransform.scale); 131 setAlpha(animateFromTransform.alpha); 132 } 133 animate().translationY(toTransform.translationY) 134 .scaleX(toTransform.scale) 135 .scaleY(toTransform.scale) 136 .alpha(toTransform.alpha) 137 .setDuration(duration) 138 .setInterpolator(BakedBezierInterpolator.INSTANCE) 139 .withLayer() 140 .start(); 141 } else { 142 setTranslationY(toTransform.translationY); 143 setScaleX(toTransform.scale); 144 setScaleY(toTransform.scale); 145 setAlpha(toTransform.alpha); 146 } 147 } 148 149 /** Returns an animator to animate this task to the specified transform */ 150 Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) { 151 AnimatorSet anims = new AnimatorSet(); 152 anims.playTogether( 153 ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY), 154 ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale), 155 ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale), 156 ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha) 157 ); 158 return anims; 159 } 160 161 /** Resets this view's properties */ 162 void resetViewProperties() { 163 setTranslationX(0f); 164 setTranslationY(0f); 165 setScaleX(1f); 166 setScaleY(1f); 167 setAlpha(1f); 168 } 169 170 void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) { 171 // Fade the view out and slide it away 172 toTransform.alpha = 0f; 173 toTransform.translationY += 200; 174 } 175 176 void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) { 177 // Fade the view in 178 fromTransform.alpha = 0f; 179 } 180 181 /** Animates this task view as it enters recents */ 182 public void animateOnEnterRecents() { 183 RecentsConfiguration config = RecentsConfiguration.getInstance(); 184 int translate = config.pxFromDp(10); 185 mBarView.setScaleX(1.25f); 186 mBarView.setScaleY(1.25f); 187 mBarView.setAlpha(0f); 188 mBarView.setTranslationX(translate / 2); 189 mBarView.setTranslationY(-translate); 190 mBarView.animate() 191 .alpha(1f) 192 .scaleX(1f) 193 .scaleY(1f) 194 .translationX(0) 195 .translationY(0) 196 .setStartDelay(235) 197 .setInterpolator(BakedBezierInterpolator.INSTANCE) 198 .setDuration(Utilities.calculateTranslationAnimationDuration(translate)) 199 .withLayer() 200 .start(); 201 } 202 203 /** Animates this task view as it exits recents */ 204 public void animateOnLeavingRecents(final Runnable r) { 205 RecentsConfiguration config = RecentsConfiguration.getInstance(); 206 int translate = config.pxFromDp(10); 207 mBarView.animate() 208 .alpha(0f) 209 .scaleX(1.1f) 210 .scaleY(1.1f) 211 .translationX(translate / 2) 212 .translationY(-translate) 213 .setStartDelay(0) 214 .setInterpolator(BakedBezierInterpolator.INSTANCE) 215 .setDuration(Utilities.calculateTranslationAnimationDuration(translate)) 216 .withLayer() 217 .withEndAction(r) 218 .start(); 219 } 220 221 /** Returns the rect we want to clip (it may not be the full rect) */ 222 Rect getClippingRect(Rect outRect, boolean accountForRoundedRects) { 223 getHitRect(outRect); 224 // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster 225 outRect.right = outRect.left + mThumbnailView.getRight(); 226 outRect.bottom = outRect.top + mThumbnailView.getBottom(); 227 // We need to shrink the next rect by the rounded corners since those are draw on 228 // top of the current view 229 if (accountForRoundedRects) { 230 RecentsConfiguration config = RecentsConfiguration.getInstance(); 231 float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps); 232 outRect.inset((int) radius, (int) radius); 233 } 234 return outRect; 235 } 236 237 /** Enable the hw layers on this task view */ 238 void enableHwLayers() { 239 mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null); 240 } 241 242 /** Disable the hw layers on this task view */ 243 void disableHwLayers() { 244 mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null); 245 } 246 247 /**** TaskCallbacks Implementation ****/ 248 249 /** Binds this task view to the task */ 250 public void onTaskBound(Task t) { 251 mTask = t; 252 mTask.setCallbacks(this); 253 } 254 255 @Override 256 public void onTaskDataLoaded(boolean reloadingTaskData) { 257 if (mThumbnailView != null && mBarView != null) { 258 // Bind each of the views to the new task data 259 mThumbnailView.rebindToTask(mTask, reloadingTaskData); 260 mBarView.rebindToTask(mTask, reloadingTaskData); 261 } 262 mTaskDataLoaded = true; 263 } 264 265 @Override 266 public void onTaskDataUnloaded() { 267 if (mThumbnailView != null && mBarView != null) { 268 // Unbind each of the views from the task data and remove the task callback 269 mTask.setCallbacks(null); 270 mThumbnailView.unbindFromTask(); 271 mBarView.unbindFromTask(); 272 } 273 mTaskDataLoaded = false; 274 } 275 276 @Override 277 public void onClick(View v) { 278 mCb.onTaskIconClicked(this); 279 } 280}