blob: e04a1b26ef3433b291a8e91329a9a39b95a162a0 [file] [log] [blame]
Winson Chung303e1ff2014-03-07 15:06:19 -08001/*
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
Winson Chungc6a16232014-04-01 14:04:48 -070019import android.animation.Animator;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
Winson Chung303e1ff2014-03-07 15:06:19 -080022import android.content.Context;
23import android.graphics.Canvas;
Winson Chung303e1ff2014-03-07 15:06:19 -080024import android.graphics.Path;
Winson Chung303e1ff2014-03-07 15:06:19 -080025import android.graphics.Rect;
26import android.graphics.RectF;
Winson Chung37c8d8e2014-03-24 14:53:07 -070027import android.util.AttributeSet;
Winson Chung303e1ff2014-03-07 15:06:19 -080028import android.view.View;
29import android.view.animation.AccelerateDecelerateInterpolator;
Winson Chung303e1ff2014-03-07 15:06:19 -080030import android.view.animation.DecelerateInterpolator;
31import android.widget.FrameLayout;
Winson Chung37c8d8e2014-03-24 14:53:07 -070032import com.android.systemui.R;
Winson Chung303e1ff2014-03-07 15:06:19 -080033import com.android.systemui.recents.Constants;
34import com.android.systemui.recents.RecentsConfiguration;
35import com.android.systemui.recents.model.Task;
Winson Chung303e1ff2014-03-07 15:06:19 -080036
Winson Chung303e1ff2014-03-07 15:06:19 -080037
Winson Chung37c8d8e2014-03-24 14:53:07 -070038/* 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
Winson Chung303e1ff2014-03-07 15:06:19 -080046 Task mTask;
Winson Chung37c8d8e2014-03-24 14:53:07 -070047 boolean mTaskDataLoaded;
48
49 TaskThumbnailView mThumbnailView;
50 TaskBarView mBarView;
51 TaskViewCallbacks mCb;
Winson Chung303e1ff2014-03-07 15:06:19 -080052
53 Path mRoundedRectClipPath = new Path();
54
Winson Chung37c8d8e2014-03-24 14:53:07 -070055
56 public TaskView(Context context) {
57 this(context, null);
Winson Chung303e1ff2014-03-07 15:06:19 -080058 }
59
Winson Chung37c8d8e2014-03-24 14:53:07 -070060 public TaskView(Context context, AttributeSet attrs) {
61 this(context, attrs, 0);
62 }
Winson Chung303e1ff2014-03-07 15:06:19 -080063
Winson Chung37c8d8e2014-03-24 14:53:07 -070064 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);
Winson Chungc6a16232014-04-01 14:04:48 -070078 mBarView.mActivityIcon.setOnClickListener(this);
Winson Chung37c8d8e2014-03-24 14:53:07 -070079 if (mTaskDataLoaded) {
80 onTaskDataLoaded(false);
Winson Chung303e1ff2014-03-07 15:06:19 -080081 }
82 }
83
Winson Chung303e1ff2014-03-07 15:06:19 -080084 @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
Winson Chungc6a16232014-04-01 14:04:48 -070097 protected void dispatchDraw(Canvas canvas) {
98 int restoreCount = 0;
Winson Chung303e1ff2014-03-07 15:06:19 -080099 if (Constants.Values.TaskView.UseRoundedCorners) {
Winson Chungc6a16232014-04-01 14:04:48 -0700100 restoreCount = canvas.save();
Winson Chung303e1ff2014-03-07 15:06:19 -0800101 canvas.clipPath(mRoundedRectClipPath);
102 }
Winson Chungc6a16232014-04-01 14:04:48 -0700103 super.dispatchDraw(canvas);
104 if (Constants.Values.TaskView.UseRoundedCorners) {
105 canvas.restoreToCount(restoreCount);
106 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800107 }
108
Winson Chung04dfe0d2014-03-14 14:06:29 -0700109 /** Set callback */
110 void setCallbacks(TaskViewCallbacks cb) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800111 mCb = cb;
112 }
113
Winson Chung303e1ff2014-03-07 15:06:19 -0800114 /** Gets the task */
115 Task getTask() {
116 return mTask;
117 }
118
119 /** Synchronizes this view's properties with the task's transform */
Winson Chungc6a16232014-04-01 14:04:48 -0700120 void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
121 TaskViewTransform toTransform, int duration) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800122 if (duration > 0) {
123 if (animateFromTransform != null) {
124 setTranslationY(animateFromTransform.translationY);
125 setScaleX(animateFromTransform.scale);
126 setScaleY(animateFromTransform.scale);
Winson Chungc6a16232014-04-01 14:04:48 -0700127 setAlpha(animateFromTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800128 }
Winson Chungc6a16232014-04-01 14:04:48 -0700129 animate().translationY(toTransform.translationY)
130 .scaleX(toTransform.scale)
131 .scaleY(toTransform.scale)
132 .alpha(toTransform.alpha)
Winson Chung303e1ff2014-03-07 15:06:19 -0800133 .setDuration(duration)
134 .setInterpolator(new AccelerateDecelerateInterpolator())
Winson Chungc6a16232014-04-01 14:04:48 -0700135 .withLayer()
Winson Chung303e1ff2014-03-07 15:06:19 -0800136 .start();
137 } else {
Winson Chungc6a16232014-04-01 14:04:48 -0700138 setTranslationY(toTransform.translationY);
139 setScaleX(toTransform.scale);
140 setScaleY(toTransform.scale);
141 setAlpha(toTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800142 }
143 }
144
Winson Chungc6a16232014-04-01 14:04:48 -0700145 /** 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
Winson Chung303e1ff2014-03-07 15:06:19 -0800157 /** 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
Winson Chungc6a16232014-04-01 14:04:48 -0700166 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
Winson Chung303e1ff2014-03-07 15:06:19 -0800177 /** Animates this task view as it enters recents */
178 public void animateOnEnterRecents() {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700179 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();
Winson Chung303e1ff2014-03-07 15:06:19 -0800196 }
197
198 /** Animates this task view as it exits recents */
199 public void animateOnLeavingRecents(final Runnable r) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700200 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();
Winson Chung303e1ff2014-03-07 15:06:19 -0800214 }
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() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800234 mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
235 }
236
237 /** Disable the hw layers on this task view */
238 void disableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800239 mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
240 }
241
Winson Chung4d7b0922014-03-13 17:14:17 -0700242 /**** TaskCallbacks Implementation ****/
243
Winson Chung04dfe0d2014-03-14 14:06:29 -0700244 /** Binds this task view to the task */
245 public void onTaskBound(Task t) {
246 mTask = t;
247 mTask.setCallbacks(this);
Winson Chung303e1ff2014-03-07 15:06:19 -0800248 }
249
250 @Override
Winson Chung4c71aef2014-03-21 15:15:11 -0700251 public void onTaskDataLoaded(boolean reloadingTaskData) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700252 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;
Winson Chung4d7b0922014-03-13 17:14:17 -0700258 }
259
260 @Override
Winson Chung04dfe0d2014-03-14 14:06:29 -0700261 public void onTaskDataUnloaded() {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700262 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;
Winson Chung4d7b0922014-03-13 17:14:17 -0700269 }
270
271 @Override
Winson Chung303e1ff2014-03-07 15:06:19 -0800272 public void onClick(View v) {
273 mCb.onTaskIconClicked(this);
274 }
275}