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