blob: f84d564aae7a7a8c6bdfc2fd53b4d2250585f06a [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 Chunga26fb782014-06-12 17:52:39 -070019import android.animation.ObjectAnimator;
Winson Chung14926462014-04-14 18:57:14 -070020import android.animation.TimeInterpolator;
21import android.animation.ValueAnimator;
Winson Chung303e1ff2014-03-07 15:06:19 -080022import android.content.Context;
Winson Chung14926462014-04-14 18:57:14 -070023import android.graphics.Canvas;
Winson Chung96e3bc12014-05-06 16:44:12 -070024import android.graphics.Outline;
Winson Chung14926462014-04-14 18:57:14 -070025import android.graphics.Path;
Winson Chung9f9679d2014-04-11 16:49:09 -070026import android.graphics.Point;
Winson Chung303e1ff2014-03-07 15:06:19 -080027import android.graphics.Rect;
Winson Chung14926462014-04-14 18:57:14 -070028import android.graphics.RectF;
Winson Chung37c8d8e2014-03-24 14:53:07 -070029import android.util.AttributeSet;
Winson Chung9f9679d2014-04-11 16:49:09 -070030import android.view.MotionEvent;
Winson Chung303e1ff2014-03-07 15:06:19 -080031import android.view.View;
Winson Chung14926462014-04-14 18:57:14 -070032import android.view.animation.AccelerateInterpolator;
Winson Chung303e1ff2014-03-07 15:06:19 -080033import android.widget.FrameLayout;
Winson Chung37c8d8e2014-03-24 14:53:07 -070034import com.android.systemui.R;
Winson Chungd42a6cf2014-06-03 16:24:04 -070035import com.android.systemui.recents.Console;
Winson Chung14926462014-04-14 18:57:14 -070036import com.android.systemui.recents.Constants;
Winson Chung303e1ff2014-03-07 15:06:19 -080037import com.android.systemui.recents.RecentsConfiguration;
38import com.android.systemui.recents.model.Task;
Winson Chung303e1ff2014-03-07 15:06:19 -080039
Winson Chung303e1ff2014-03-07 15:06:19 -080040
Winson Chung37c8d8e2014-03-24 14:53:07 -070041/* A task view */
Winson Chung6cb485f2014-05-19 10:30:43 -070042public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.OnClickListener,
43 View.OnLongClickListener {
Winson Chung37c8d8e2014-03-24 14:53:07 -070044 /** The TaskView callbacks */
45 interface TaskViewCallbacks {
46 public void onTaskIconClicked(TaskView tv);
Winson Chung9f9679d2014-04-11 16:49:09 -070047 public void onTaskAppInfoClicked(TaskView tv);
Winson Chung47a3e652014-05-21 16:03:42 -070048 public void onTaskFocused(TaskView tv);
Winson Chung54e297a2014-05-09 17:15:32 -070049 public void onTaskDismissed(TaskView tv);
Winson Chung37c8d8e2014-03-24 14:53:07 -070050 }
51
Winson Chungd42a6cf2014-06-03 16:24:04 -070052 RecentsConfiguration mConfig;
53
Winson Chung14926462014-04-14 18:57:14 -070054 int mDim;
55 int mMaxDim;
56 TimeInterpolator mDimInterpolator = new AccelerateInterpolator();
57
Winson Chung303e1ff2014-03-07 15:06:19 -080058 Task mTask;
Winson Chung37c8d8e2014-03-24 14:53:07 -070059 boolean mTaskDataLoaded;
Winson Chung1e8d71b2014-05-16 17:05:22 -070060 boolean mIsFocused;
Winson Chung5a9b0b02014-05-20 17:32:03 -070061 boolean mClipViewInStack;
Winson Chung9f9679d2014-04-11 16:49:09 -070062 Point mLastTouchDown = new Point();
Winson Chung14926462014-04-14 18:57:14 -070063 Path mRoundedRectClipPath = new Path();
Winson Chungd42a6cf2014-06-03 16:24:04 -070064 Rect mTmpRect = new Rect();
Winson Chung37c8d8e2014-03-24 14:53:07 -070065
66 TaskThumbnailView mThumbnailView;
67 TaskBarView mBarView;
68 TaskViewCallbacks mCb;
Winson Chung303e1ff2014-03-07 15:06:19 -080069
Winson Chungd42a6cf2014-06-03 16:24:04 -070070 // Optimizations
71 ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
72 new ValueAnimator.AnimatorUpdateListener() {
73 @Override
74 public void onAnimationUpdate(ValueAnimator animation) {
75 updateDimOverlayFromScale();
76 }
77 };
Winson Chung743d5c92014-06-13 10:14:53 -070078 Runnable mEnableThumbnailClip = new Runnable() {
79 @Override
80 public void run() {
81 mThumbnailView.updateTaskBarClip(mBarView);
82 }
83 };
84 Runnable mDisableThumbnailClip = new Runnable() {
85 @Override
86 public void run() {
87 mThumbnailView.disableClipTaskBarView();
88 }
89 };
Winson Chungd42a6cf2014-06-03 16:24:04 -070090
Winson Chung37c8d8e2014-03-24 14:53:07 -070091
92 public TaskView(Context context) {
93 this(context, null);
Winson Chung303e1ff2014-03-07 15:06:19 -080094 }
95
Winson Chung37c8d8e2014-03-24 14:53:07 -070096 public TaskView(Context context, AttributeSet attrs) {
97 this(context, attrs, 0);
98 }
Winson Chung303e1ff2014-03-07 15:06:19 -080099
Winson Chung37c8d8e2014-03-24 14:53:07 -0700100 public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
101 this(context, attrs, defStyleAttr, 0);
102 }
103
104 public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
105 super(context, attrs, defStyleAttr, defStyleRes);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700106 mConfig = RecentsConfiguration.getInstance();
Winson Chung14926462014-04-14 18:57:14 -0700107 setWillNotDraw(false);
Winson Chunga26fb782014-06-12 17:52:39 -0700108 setDim(getDim());
Winson Chung37c8d8e2014-03-24 14:53:07 -0700109 }
110
111 @Override
112 protected void onFinishInflate() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700113 mMaxDim = mConfig.taskStackMaxDim;
Winson Chung14926462014-04-14 18:57:14 -0700114
Winson Chung5a9b0b02014-05-20 17:32:03 -0700115 // By default, all views are clipped to other views in their stack
116 mClipViewInStack = true;
117
Winson Chung37c8d8e2014-03-24 14:53:07 -0700118 // Bind the views
Winson Chung37c8d8e2014-03-24 14:53:07 -0700119 mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
Winson Chung743d5c92014-06-13 10:14:53 -0700120 mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
Winson Chung9f9679d2014-04-11 16:49:09 -0700121
Winson Chung37c8d8e2014-03-24 14:53:07 -0700122 if (mTaskDataLoaded) {
123 onTaskDataLoaded(false);
Winson Chung303e1ff2014-03-07 15:06:19 -0800124 }
125 }
126
Winson Chung9f9679d2014-04-11 16:49:09 -0700127 @Override
Winson Chung14926462014-04-14 18:57:14 -0700128 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
129 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
130
131 // Update the rounded rect clip path
Winson Chungd42a6cf2014-06-03 16:24:04 -0700132 float radius = mConfig.taskViewRoundedCornerRadiusPx;
Winson Chung14926462014-04-14 18:57:14 -0700133 mRoundedRectClipPath.reset();
134 mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
135 radius, radius, Path.Direction.CW);
Winson Chung96e3bc12014-05-06 16:44:12 -0700136
137 // Update the outline
138 Outline o = new Outline();
Winson Chung602de032014-05-27 12:19:28 -0700139 o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight() -
Winson Chungd42a6cf2014-06-03 16:24:04 -0700140 mConfig.taskViewShadowOutlineBottomInsetPx, radius);
Winson Chung96e3bc12014-05-06 16:44:12 -0700141 setOutline(o);
Winson Chung14926462014-04-14 18:57:14 -0700142 }
143
144 @Override
Winson Chung9f9679d2014-04-11 16:49:09 -0700145 public boolean onInterceptTouchEvent(MotionEvent ev) {
146 switch (ev.getAction()) {
147 case MotionEvent.ACTION_DOWN:
148 case MotionEvent.ACTION_MOVE:
149 mLastTouchDown.set((int) ev.getX(), (int) ev.getY());
150 break;
151 }
152 return super.onInterceptTouchEvent(ev);
153 }
154
Winson Chung04dfe0d2014-03-14 14:06:29 -0700155 /** Set callback */
156 void setCallbacks(TaskViewCallbacks cb) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800157 mCb = cb;
158 }
159
Winson Chung303e1ff2014-03-07 15:06:19 -0800160 /** Gets the task */
161 Task getTask() {
162 return mTask;
163 }
164
165 /** Synchronizes this view's properties with the task's transform */
Winson Chungc6a16232014-04-01 14:04:48 -0700166 void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
167 TaskViewTransform toTransform, int duration) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700168 if (Console.Enabled) {
169 Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]",
170 "duration: " + duration, Console.AnsiPurple);
171 }
Winson Chung96e3bc12014-05-06 16:44:12 -0700172
Winson Chung54e297a2014-05-09 17:15:32 -0700173 // Update the bar view
174 mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
175
176 // Update this task view
Winson Chung303e1ff2014-03-07 15:06:19 -0800177 if (duration > 0) {
178 if (animateFromTransform != null) {
179 setTranslationY(animateFromTransform.translationY);
Winson Chung814086d2014-05-07 15:01:14 -0700180 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700181 setTranslationZ(animateFromTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700182 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800183 setScaleX(animateFromTransform.scale);
184 setScaleY(animateFromTransform.scale);
Winson Chungc6a16232014-04-01 14:04:48 -0700185 setAlpha(animateFromTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800186 }
Winson Chung814086d2014-05-07 15:01:14 -0700187 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700188 animate().translationZ(toTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700189 }
Winson Chungc6a16232014-04-01 14:04:48 -0700190 animate().translationY(toTransform.translationY)
191 .scaleX(toTransform.scale)
192 .scaleY(toTransform.scale)
193 .alpha(toTransform.alpha)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700194 .setStartDelay(0)
Winson Chung303e1ff2014-03-07 15:06:19 -0800195 .setDuration(duration)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700196 .setInterpolator(mConfig.fastOutSlowInInterpolator)
197 .setUpdateListener(mUpdateDimListener)
Winson Chung303e1ff2014-03-07 15:06:19 -0800198 .start();
199 } else {
Winson Chungc6a16232014-04-01 14:04:48 -0700200 setTranslationY(toTransform.translationY);
Winson Chung814086d2014-05-07 15:01:14 -0700201 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700202 setTranslationZ(toTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700203 }
Winson Chungc6a16232014-04-01 14:04:48 -0700204 setScaleX(toTransform.scale);
205 setScaleY(toTransform.scale);
206 setAlpha(toTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800207 }
Winson Chung14926462014-04-14 18:57:14 -0700208 updateDimOverlayFromScale();
209 invalidate();
Winson Chung303e1ff2014-03-07 15:06:19 -0800210 }
211
212 /** Resets this view's properties */
213 void resetViewProperties() {
214 setTranslationX(0f);
215 setTranslationY(0f);
Winson Chung814086d2014-05-07 15:01:14 -0700216 if (Constants.DebugFlags.App.EnableShadows) {
217 setTranslationZ(0f);
218 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800219 setScaleX(1f);
220 setScaleY(1f);
221 setAlpha(1f);
Winson Chunga26fb782014-06-12 17:52:39 -0700222 setDim(0);
Winson Chung14926462014-04-14 18:57:14 -0700223 invalidate();
Winson Chung303e1ff2014-03-07 15:06:19 -0800224 }
225
Winson Chung11ca76a52014-04-10 17:29:13 -0700226 /**
227 * When we are un/filtering, this method will set up the transform that we are animating to,
228 * in order to hide the task.
229 */
Winson Chungc6a16232014-04-01 14:04:48 -0700230 void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
231 // Fade the view out and slide it away
232 toTransform.alpha = 0f;
233 toTransform.translationY += 200;
234 }
235
Winson Chung11ca76a52014-04-10 17:29:13 -0700236 /**
237 * When we are un/filtering, this method will setup the transform that we are animating from,
238 * in order to show the task.
239 */
Winson Chungc6a16232014-04-01 14:04:48 -0700240 void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
241 // Fade the view in
242 fromTransform.alpha = 0f;
243 }
244
Winson Chung24cf1522014-05-29 12:03:33 -0700245 /** Prepares this task view for the enter-recents animations. This is called earlier in the
246 * first layout because the actual animation into recents may take a long time. */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700247 public void prepareAnimateEnterRecents(boolean isTaskViewFrontMost, int offsetY, int offscreenY,
248 Rect taskRect) {
249 if (mConfig.launchedFromAppWithScreenshot) {
250 if (isTaskViewFrontMost) {
251 // Hide the task view as we are going to animate the full screenshot into view
252 // and then replace it with this view once we are done
253 setVisibility(View.INVISIBLE);
254 // Also hide the front most task bar view so we can animate it in
255 mBarView.prepareAnimateEnterRecents();
256 } else {
257 // Top align the task views
258 setTranslationY(offsetY);
259 setScaleX(1f);
260 setScaleY(1f);
261 }
262
263 } else if (mConfig.launchedFromAppWithThumbnail) {
264 if (isTaskViewFrontMost) {
265 // Hide the front most task bar view so we can animate it in
266 mBarView.prepareAnimateEnterRecents();
Winson Chunga26fb782014-06-12 17:52:39 -0700267 // Set the dim to 0 so we can animate it in
268 setDim(0);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700269 }
270
271 } else if (mConfig.launchedFromHome) {
272 // Move the task view off screen (below) so we can animate it in
273 setTranslationY(offscreenY);
274 setScaleX(1f);
275 setScaleY(1f);
276 }
Winson Chung24cf1522014-05-29 12:03:33 -0700277 }
278
Winson Chung303e1ff2014-03-07 15:06:19 -0800279 /** Animates this task view as it enters recents */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700280 public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx) {
281 TaskViewTransform transform = ctx.transform;
282
283 if (mConfig.launchedFromAppWithScreenshot) {
284 if (ctx.isFrontMost) {
285 // Animate the full screenshot down first, before swapping with this task view
286 ctx.fullScreenshot.animateOnEnterRecents(ctx, new Runnable() {
287 @Override
288 public void run() {
289 // Animate the task bar of the first task view
Winson Chung743d5c92014-06-13 10:14:53 -0700290 mBarView.animateOnEnterRecents(0, mEnableThumbnailClip);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700291 setVisibility(View.VISIBLE);
292 }
293 });
294 } else {
295 // Animate the tasks down behind the full screenshot
296 animate()
297 .scaleX(transform.scale)
298 .scaleY(transform.scale)
299 .translationY(transform.translationY)
300 .setStartDelay(0)
301 .setInterpolator(mConfig.linearOutSlowInInterpolator)
302 .setDuration(475)
303 .withLayer()
Winson Chung743d5c92014-06-13 10:14:53 -0700304 .withEndAction(mEnableThumbnailClip)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700305 .start();
306 }
307
308 } else if (mConfig.launchedFromAppWithThumbnail) {
309 if (ctx.isFrontMost) {
310 // Animate the task bar of the first task view
Winson Chung743d5c92014-06-13 10:14:53 -0700311 mBarView.animateOnEnterRecents(mConfig.taskBarEnterAnimDelay, mEnableThumbnailClip);
312
Winson Chunga26fb782014-06-12 17:52:39 -0700313 // Animate the dim into view as well
314 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", getDimOverlayFromScale());
315 anim.setStartDelay(mConfig.taskBarEnterAnimDelay);
316 anim.setDuration(mConfig.taskBarEnterAnimDuration);
317 anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
318 anim.start();
Winson Chung743d5c92014-06-13 10:14:53 -0700319 } else {
320 mEnableThumbnailClip.run();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700321 }
322
323 } else if (mConfig.launchedFromHome) {
324 // Animate the tasks up
325 int frontIndex = (ctx.stackViewCount - ctx.stackViewIndex - 1);
326 int delay = mConfig.taskBarEnterAnimDelay +
327 frontIndex * mConfig.taskViewEnterFromHomeDelay;
328 animate()
329 .scaleX(transform.scale)
330 .scaleY(transform.scale)
331 .translationY(transform.translationY)
332 .setStartDelay(delay)
333 .setInterpolator(mConfig.quintOutInterpolator)
334 .setDuration(mConfig.taskViewEnterFromHomeDuration)
335 .withLayer()
Winson Chung743d5c92014-06-13 10:14:53 -0700336 .withEndAction(mEnableThumbnailClip)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700337 .start();
338 }
339 }
340
341 /** Animates this task view as it leaves recents */
342 public void animateOnExitRecents(ViewAnimation.TaskViewExitContext ctx) {
343 animate()
344 .translationY(ctx.offscreenTranslationY)
345 .setStartDelay(0)
Winson Chungad6f2762014-06-13 09:41:09 -0700346 .setInterpolator(mConfig.fastOutLinearInInterpolator)
347 .setDuration(mConfig.taskViewExitToHomeDuration)
Winson Chung37c8d8e2014-03-24 14:53:07 -0700348 .withLayer()
Winson Chungd42a6cf2014-06-03 16:24:04 -0700349 .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
Winson Chung37c8d8e2014-03-24 14:53:07 -0700350 .start();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700351 ctx.postAnimationTrigger.increment();
Winson Chung303e1ff2014-03-07 15:06:19 -0800352 }
353
Winson Chunga26fb782014-06-12 17:52:39 -0700354 /** Animates this task view if the user does not interact with the stack after a certain time. */
355 public void animateOnNoUserInteraction() {
356 mBarView.animateOnNoUserInteraction();
357 }
358
359 /** Mark this task view that the user does has not interacted with the stack after a certain time. */
360 public void setOnNoUserInteraction() {
361 mBarView.setOnNoUserInteraction();
362 }
363
Winson Chung303e1ff2014-03-07 15:06:19 -0800364 /** Animates this task view as it exits recents */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700365 public void animateOnLaunchingTask(final Runnable r) {
Winson Chung743d5c92014-06-13 10:14:53 -0700366 // Disable the thumbnail clip and animate the bar out
367 mBarView.animateOnLaunchingTask(mDisableThumbnailClip, r);
Winson Chunga26fb782014-06-12 17:52:39 -0700368
369 // Animate the dim
370 if (mDim > 0) {
371 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
372 anim.setDuration(mConfig.taskBarExitAnimDuration);
373 anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
374 anim.start();
375 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800376 }
377
Winson Chung9f49df92014-05-07 18:08:34 -0700378 /** Animates the deletion of this task view */
379 public void animateRemoval(final Runnable r) {
Winson Chung5a9b0b02014-05-20 17:32:03 -0700380 // Disabling clipping with the stack while the view is animating away
381 setClipViewInStack(false);
382
Winson Chungd42a6cf2014-06-03 16:24:04 -0700383 animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
Winson Chung9f49df92014-05-07 18:08:34 -0700384 .alpha(0f)
385 .setStartDelay(0)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700386 .setInterpolator(mConfig.fastOutSlowInInterpolator)
387 .setDuration(mConfig.taskViewRemoveAnimDuration)
Winson Chung9f49df92014-05-07 18:08:34 -0700388 .withLayer()
389 .withEndAction(new Runnable() {
390 @Override
391 public void run() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700392 // We just throw this into a runnable because starting a view property
393 // animation using layers can cause inconsisten results if we try and
394 // update the layers while the animation is running. In some cases,
395 // the runnabled passed in may start an animation which also uses layers
396 // so we defer all this by posting this.
397 r.run();
Winson Chung5a9b0b02014-05-20 17:32:03 -0700398
399 // Re-enable clipping with the stack (we will reuse this view)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700400 setClipViewInStack(true);
Winson Chung9f49df92014-05-07 18:08:34 -0700401 }
402 })
403 .start();
404 }
405
Winson Chung303e1ff2014-03-07 15:06:19 -0800406 /** Returns the rect we want to clip (it may not be the full rect) */
Winson Chung0d767552014-04-09 14:33:23 -0700407 Rect getClippingRect(Rect outRect) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800408 getHitRect(outRect);
409 // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
410 outRect.right = outRect.left + mThumbnailView.getRight();
411 outRect.bottom = outRect.top + mThumbnailView.getBottom();
Winson Chung303e1ff2014-03-07 15:06:19 -0800412 return outRect;
413 }
414
415 /** Enable the hw layers on this task view */
416 void enableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800417 mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700418 mBarView.enableHwLayers();
Winson Chung303e1ff2014-03-07 15:06:19 -0800419 }
420
421 /** Disable the hw layers on this task view */
422 void disableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800423 mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700424 mBarView.disableHwLayers();
Winson Chung303e1ff2014-03-07 15:06:19 -0800425 }
426
Winson Chung5a9b0b02014-05-20 17:32:03 -0700427 /**
428 * Returns whether this view should be clipped, or any views below should clip against this
429 * view.
430 */
431 boolean shouldClipViewInStack() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700432 return mClipViewInStack && (getVisibility() == View.VISIBLE);
Winson Chung5a9b0b02014-05-20 17:32:03 -0700433 }
434
435 /** Sets whether this view should be clipped, or clipped against. */
436 void setClipViewInStack(boolean clip) {
437 if (clip != mClipViewInStack) {
438 mClipViewInStack = clip;
439 if (getParent() instanceof View) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700440 getHitRect(mTmpRect);
441 ((View) getParent()).invalidate(mTmpRect);
Winson Chung5a9b0b02014-05-20 17:32:03 -0700442 }
443 }
444 }
445
Winson Chunga26fb782014-06-12 17:52:39 -0700446 /** Returns the current dim. */
447 public void setDim(int dim) {
448 mDim = dim;
449 postInvalidateOnAnimation();
450 }
451
452 /** Returns the current dim. */
453 public int getDim() {
454 return mDim;
455 }
456
457 /** Compute the dim as a function of the scale of this view. */
458 int getDimOverlayFromScale() {
Winson Chung14926462014-04-14 18:57:14 -0700459 float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
460 float scaleRange = 1f - minScale;
461 float dim = (1f - getScaleX()) / scaleRange;
462 dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
Winson Chunga26fb782014-06-12 17:52:39 -0700463 return Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
464 }
465
466 /** Update the dim as a function of the scale of this view. */
467 void updateDimOverlayFromScale() {
468 setDim(getDimOverlayFromScale());
Winson Chung14926462014-04-14 18:57:14 -0700469 }
470
471 @Override
472 public void draw(Canvas canvas) {
473 // Apply the rounded rect clip path on the whole view
474 canvas.clipPath(mRoundedRectClipPath);
475
476 super.draw(canvas);
477
478 // Apply the dim if necessary
479 if (mDim > 0) {
480 canvas.drawColor(mDim << 24);
481 }
482 }
483
Winson Chung1e8d71b2014-05-16 17:05:22 -0700484 /**
485 * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
486 * if the view is not currently visible, or we are in touch state (where we still want to keep
487 * track of focus).
488 */
489 public void setFocusedTask() {
490 mIsFocused = true;
491 requestFocus();
Winson Chung47a3e652014-05-21 16:03:42 -0700492 invalidate();
493 mCb.onTaskFocused(this);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700494 }
495
496 /**
497 * Updates the explicitly focused state when the view focus changes.
498 */
499 @Override
500 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
501 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
502 if (!gainFocus) {
503 mIsFocused = false;
Winson Chung47a3e652014-05-21 16:03:42 -0700504 invalidate();
Winson Chung1e8d71b2014-05-16 17:05:22 -0700505 }
506 }
507
508 /**
509 * Returns whether we have explicitly been focused.
510 */
511 public boolean isFocusedTask() {
512 return mIsFocused || isFocused();
513 }
514
Winson Chung4d7b0922014-03-13 17:14:17 -0700515 /**** TaskCallbacks Implementation ****/
516
Winson Chung04dfe0d2014-03-14 14:06:29 -0700517 /** Binds this task view to the task */
518 public void onTaskBound(Task t) {
519 mTask = t;
520 mTask.setCallbacks(this);
Winson Chung303e1ff2014-03-07 15:06:19 -0800521 }
522
523 @Override
Winson Chung4c71aef2014-03-21 15:15:11 -0700524 public void onTaskDataLoaded(boolean reloadingTaskData) {
Winson Chung863db8a2014-05-20 14:27:39 -0700525 if (mThumbnailView != null && mBarView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700526 // Bind each of the views to the new task data
527 mThumbnailView.rebindToTask(mTask, reloadingTaskData);
528 mBarView.rebindToTask(mTask, reloadingTaskData);
Winson Chung9f9679d2014-04-11 16:49:09 -0700529 // Rebind any listeners
530 mBarView.mApplicationIcon.setOnClickListener(this);
Winson Chung54e297a2014-05-09 17:15:32 -0700531 mBarView.mDismissButton.setOnClickListener(this);
Winson Chung6cb485f2014-05-19 10:30:43 -0700532 if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700533 if (mConfig.developerOptionsEnabled) {
Winson Chung6cb485f2014-05-19 10:30:43 -0700534 mBarView.mApplicationIcon.setOnLongClickListener(this);
535 }
536 }
Winson Chung37c8d8e2014-03-24 14:53:07 -0700537 }
538 mTaskDataLoaded = true;
Winson Chung4d7b0922014-03-13 17:14:17 -0700539 }
540
541 @Override
Winson Chung04dfe0d2014-03-14 14:06:29 -0700542 public void onTaskDataUnloaded() {
Winson Chung863db8a2014-05-20 14:27:39 -0700543 if (mThumbnailView != null && mBarView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700544 // Unbind each of the views from the task data and remove the task callback
545 mTask.setCallbacks(null);
546 mThumbnailView.unbindFromTask();
547 mBarView.unbindFromTask();
Winson Chung9f9679d2014-04-11 16:49:09 -0700548 // Unbind any listeners
549 mBarView.mApplicationIcon.setOnClickListener(null);
Winson Chung6cb485f2014-05-19 10:30:43 -0700550 mBarView.mDismissButton.setOnClickListener(null);
551 if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
552 mBarView.mApplicationIcon.setOnLongClickListener(null);
553 }
Winson Chung37c8d8e2014-03-24 14:53:07 -0700554 }
555 mTaskDataLoaded = false;
Winson Chung4d7b0922014-03-13 17:14:17 -0700556 }
557
558 @Override
Winson Chung303e1ff2014-03-07 15:06:19 -0800559 public void onClick(View v) {
Winson Chung863db8a2014-05-20 14:27:39 -0700560 if (v == mBarView.mApplicationIcon) {
Winson Chung9f9679d2014-04-11 16:49:09 -0700561 mCb.onTaskIconClicked(this);
Winson Chung54e297a2014-05-09 17:15:32 -0700562 } else if (v == mBarView.mDismissButton) {
563 // Animate out the view and call the callback
564 final TaskView tv = this;
565 animateRemoval(new Runnable() {
566 @Override
567 public void run() {
568 mCb.onTaskDismissed(tv);
569 }
570 });
Winson Chung9f9679d2014-04-11 16:49:09 -0700571 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800572 }
Winson Chung6cb485f2014-05-19 10:30:43 -0700573
574 @Override
575 public boolean onLongClick(View v) {
576 if (v == mBarView.mApplicationIcon) {
577 mCb.onTaskAppInfoClicked(this);
578 return true;
579 }
580 return false;
581 }
Winson Chung7bb18852014-05-20 23:25:41 +0000582}