blob: 7376255b3e7b5c972e1cc938d116531216632c10 [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 Chungd42a6cf2014-06-03 16:24:04 -070032import android.view.ViewParent;
Winson Chung14926462014-04-14 18:57:14 -070033import android.view.animation.AccelerateInterpolator;
Winson Chung303e1ff2014-03-07 15:06:19 -080034import android.widget.FrameLayout;
Winson Chung37c8d8e2014-03-24 14:53:07 -070035import com.android.systemui.R;
Winson Chungd42a6cf2014-06-03 16:24:04 -070036import com.android.systemui.recents.Console;
Winson Chung14926462014-04-14 18:57:14 -070037import com.android.systemui.recents.Constants;
Winson Chung303e1ff2014-03-07 15:06:19 -080038import com.android.systemui.recents.RecentsConfiguration;
39import com.android.systemui.recents.model.Task;
Winson Chung303e1ff2014-03-07 15:06:19 -080040
Winson Chung303e1ff2014-03-07 15:06:19 -080041
Winson Chung37c8d8e2014-03-24 14:53:07 -070042/* A task view */
Winson Chung6cb485f2014-05-19 10:30:43 -070043public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.OnClickListener,
44 View.OnLongClickListener {
Winson Chung37c8d8e2014-03-24 14:53:07 -070045 /** The TaskView callbacks */
46 interface TaskViewCallbacks {
47 public void onTaskIconClicked(TaskView tv);
Winson Chung9f9679d2014-04-11 16:49:09 -070048 public void onTaskAppInfoClicked(TaskView tv);
Winson Chung47a3e652014-05-21 16:03:42 -070049 public void onTaskFocused(TaskView tv);
Winson Chung54e297a2014-05-09 17:15:32 -070050 public void onTaskDismissed(TaskView tv);
Winson Chung37c8d8e2014-03-24 14:53:07 -070051 }
52
Winson Chungd42a6cf2014-06-03 16:24:04 -070053 RecentsConfiguration mConfig;
54
Winson Chung14926462014-04-14 18:57:14 -070055 int mDim;
56 int mMaxDim;
57 TimeInterpolator mDimInterpolator = new AccelerateInterpolator();
58
Winson Chung303e1ff2014-03-07 15:06:19 -080059 Task mTask;
Winson Chung37c8d8e2014-03-24 14:53:07 -070060 boolean mTaskDataLoaded;
Winson Chung1e8d71b2014-05-16 17:05:22 -070061 boolean mIsFocused;
Winson Chung5a9b0b02014-05-20 17:32:03 -070062 boolean mClipViewInStack;
Winson Chung9f9679d2014-04-11 16:49:09 -070063 Point mLastTouchDown = new Point();
Winson Chung14926462014-04-14 18:57:14 -070064 Path mRoundedRectClipPath = new Path();
Winson Chungd42a6cf2014-06-03 16:24:04 -070065 Rect mTmpRect = new Rect();
Winson Chung37c8d8e2014-03-24 14:53:07 -070066
67 TaskThumbnailView mThumbnailView;
68 TaskBarView mBarView;
69 TaskViewCallbacks mCb;
Winson Chung303e1ff2014-03-07 15:06:19 -080070
Winson Chungd42a6cf2014-06-03 16:24:04 -070071 // Optimizations
72 ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
73 new ValueAnimator.AnimatorUpdateListener() {
74 @Override
75 public void onAnimationUpdate(ValueAnimator animation) {
76 updateDimOverlayFromScale();
77 }
78 };
79
Winson Chung37c8d8e2014-03-24 14:53:07 -070080
81 public TaskView(Context context) {
82 this(context, null);
Winson Chung303e1ff2014-03-07 15:06:19 -080083 }
84
Winson Chung37c8d8e2014-03-24 14:53:07 -070085 public TaskView(Context context, AttributeSet attrs) {
86 this(context, attrs, 0);
87 }
Winson Chung303e1ff2014-03-07 15:06:19 -080088
Winson Chung37c8d8e2014-03-24 14:53:07 -070089 public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
90 this(context, attrs, defStyleAttr, 0);
91 }
92
93 public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
94 super(context, attrs, defStyleAttr, defStyleRes);
Winson Chungd42a6cf2014-06-03 16:24:04 -070095 mConfig = RecentsConfiguration.getInstance();
Winson Chung14926462014-04-14 18:57:14 -070096 setWillNotDraw(false);
Winson Chunga26fb782014-06-12 17:52:39 -070097 setDim(getDim());
Winson Chung37c8d8e2014-03-24 14:53:07 -070098 }
99
100 @Override
101 protected void onFinishInflate() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700102 mMaxDim = mConfig.taskStackMaxDim;
Winson Chung14926462014-04-14 18:57:14 -0700103
Winson Chung5a9b0b02014-05-20 17:32:03 -0700104 // By default, all views are clipped to other views in their stack
105 mClipViewInStack = true;
106
Winson Chung37c8d8e2014-03-24 14:53:07 -0700107 // Bind the views
108 mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
109 mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
Winson Chung9f9679d2014-04-11 16:49:09 -0700110
Winson Chung37c8d8e2014-03-24 14:53:07 -0700111 if (mTaskDataLoaded) {
112 onTaskDataLoaded(false);
Winson Chung303e1ff2014-03-07 15:06:19 -0800113 }
114 }
115
Winson Chung9f9679d2014-04-11 16:49:09 -0700116 @Override
Winson Chung14926462014-04-14 18:57:14 -0700117 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
118 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
119
120 // Update the rounded rect clip path
Winson Chungd42a6cf2014-06-03 16:24:04 -0700121 float radius = mConfig.taskViewRoundedCornerRadiusPx;
Winson Chung14926462014-04-14 18:57:14 -0700122 mRoundedRectClipPath.reset();
123 mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
124 radius, radius, Path.Direction.CW);
Winson Chung96e3bc12014-05-06 16:44:12 -0700125
126 // Update the outline
127 Outline o = new Outline();
Winson Chung602de032014-05-27 12:19:28 -0700128 o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight() -
Winson Chungd42a6cf2014-06-03 16:24:04 -0700129 mConfig.taskViewShadowOutlineBottomInsetPx, radius);
Winson Chung96e3bc12014-05-06 16:44:12 -0700130 setOutline(o);
Winson Chung14926462014-04-14 18:57:14 -0700131 }
132
133 @Override
Winson Chung9f9679d2014-04-11 16:49:09 -0700134 public boolean onInterceptTouchEvent(MotionEvent ev) {
135 switch (ev.getAction()) {
136 case MotionEvent.ACTION_DOWN:
137 case MotionEvent.ACTION_MOVE:
138 mLastTouchDown.set((int) ev.getX(), (int) ev.getY());
139 break;
140 }
141 return super.onInterceptTouchEvent(ev);
142 }
143
Winson Chung04dfe0d2014-03-14 14:06:29 -0700144 /** Set callback */
145 void setCallbacks(TaskViewCallbacks cb) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800146 mCb = cb;
147 }
148
Winson Chung303e1ff2014-03-07 15:06:19 -0800149 /** Gets the task */
150 Task getTask() {
151 return mTask;
152 }
153
154 /** Synchronizes this view's properties with the task's transform */
Winson Chungc6a16232014-04-01 14:04:48 -0700155 void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
156 TaskViewTransform toTransform, int duration) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700157 if (Console.Enabled) {
158 Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]",
159 "duration: " + duration, Console.AnsiPurple);
160 }
Winson Chung96e3bc12014-05-06 16:44:12 -0700161
Winson Chung54e297a2014-05-09 17:15:32 -0700162 // Update the bar view
163 mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
164
165 // Update this task view
Winson Chung303e1ff2014-03-07 15:06:19 -0800166 if (duration > 0) {
167 if (animateFromTransform != null) {
168 setTranslationY(animateFromTransform.translationY);
Winson Chung814086d2014-05-07 15:01:14 -0700169 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700170 setTranslationZ(animateFromTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700171 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800172 setScaleX(animateFromTransform.scale);
173 setScaleY(animateFromTransform.scale);
Winson Chungc6a16232014-04-01 14:04:48 -0700174 setAlpha(animateFromTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800175 }
Winson Chung814086d2014-05-07 15:01:14 -0700176 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700177 animate().translationZ(toTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700178 }
Winson Chungc6a16232014-04-01 14:04:48 -0700179 animate().translationY(toTransform.translationY)
180 .scaleX(toTransform.scale)
181 .scaleY(toTransform.scale)
182 .alpha(toTransform.alpha)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700183 .setStartDelay(0)
Winson Chung303e1ff2014-03-07 15:06:19 -0800184 .setDuration(duration)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700185 .setInterpolator(mConfig.fastOutSlowInInterpolator)
186 .setUpdateListener(mUpdateDimListener)
Winson Chung303e1ff2014-03-07 15:06:19 -0800187 .start();
188 } else {
Winson Chungc6a16232014-04-01 14:04:48 -0700189 setTranslationY(toTransform.translationY);
Winson Chung814086d2014-05-07 15:01:14 -0700190 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700191 setTranslationZ(toTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700192 }
Winson Chungc6a16232014-04-01 14:04:48 -0700193 setScaleX(toTransform.scale);
194 setScaleY(toTransform.scale);
195 setAlpha(toTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800196 }
Winson Chung14926462014-04-14 18:57:14 -0700197 updateDimOverlayFromScale();
198 invalidate();
Winson Chung303e1ff2014-03-07 15:06:19 -0800199 }
200
201 /** Resets this view's properties */
202 void resetViewProperties() {
203 setTranslationX(0f);
204 setTranslationY(0f);
Winson Chung814086d2014-05-07 15:01:14 -0700205 if (Constants.DebugFlags.App.EnableShadows) {
206 setTranslationZ(0f);
207 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800208 setScaleX(1f);
209 setScaleY(1f);
210 setAlpha(1f);
Winson Chunga26fb782014-06-12 17:52:39 -0700211 setDim(0);
Winson Chung14926462014-04-14 18:57:14 -0700212 invalidate();
Winson Chung303e1ff2014-03-07 15:06:19 -0800213 }
214
Winson Chung11ca76a52014-04-10 17:29:13 -0700215 /**
216 * When we are un/filtering, this method will set up the transform that we are animating to,
217 * in order to hide the task.
218 */
Winson Chungc6a16232014-04-01 14:04:48 -0700219 void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
220 // Fade the view out and slide it away
221 toTransform.alpha = 0f;
222 toTransform.translationY += 200;
223 }
224
Winson Chung11ca76a52014-04-10 17:29:13 -0700225 /**
226 * When we are un/filtering, this method will setup the transform that we are animating from,
227 * in order to show the task.
228 */
Winson Chungc6a16232014-04-01 14:04:48 -0700229 void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
230 // Fade the view in
231 fromTransform.alpha = 0f;
232 }
233
Winson Chung24cf1522014-05-29 12:03:33 -0700234 /** Prepares this task view for the enter-recents animations. This is called earlier in the
235 * first layout because the actual animation into recents may take a long time. */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700236 public void prepareAnimateEnterRecents(boolean isTaskViewFrontMost, int offsetY, int offscreenY,
237 Rect taskRect) {
238 if (mConfig.launchedFromAppWithScreenshot) {
239 if (isTaskViewFrontMost) {
240 // Hide the task view as we are going to animate the full screenshot into view
241 // and then replace it with this view once we are done
242 setVisibility(View.INVISIBLE);
243 // Also hide the front most task bar view so we can animate it in
244 mBarView.prepareAnimateEnterRecents();
245 } else {
246 // Top align the task views
247 setTranslationY(offsetY);
248 setScaleX(1f);
249 setScaleY(1f);
250 }
251
252 } else if (mConfig.launchedFromAppWithThumbnail) {
253 if (isTaskViewFrontMost) {
254 // Hide the front most task bar view so we can animate it in
255 mBarView.prepareAnimateEnterRecents();
Winson Chunga26fb782014-06-12 17:52:39 -0700256 // Set the dim to 0 so we can animate it in
257 setDim(0);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700258 }
259
260 } else if (mConfig.launchedFromHome) {
261 // Move the task view off screen (below) so we can animate it in
262 setTranslationY(offscreenY);
263 setScaleX(1f);
264 setScaleY(1f);
265 }
Winson Chung24cf1522014-05-29 12:03:33 -0700266 }
267
Winson Chung303e1ff2014-03-07 15:06:19 -0800268 /** Animates this task view as it enters recents */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700269 public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx) {
270 TaskViewTransform transform = ctx.transform;
271
272 if (mConfig.launchedFromAppWithScreenshot) {
273 if (ctx.isFrontMost) {
274 // Animate the full screenshot down first, before swapping with this task view
275 ctx.fullScreenshot.animateOnEnterRecents(ctx, new Runnable() {
276 @Override
277 public void run() {
278 // Animate the task bar of the first task view
279 mBarView.animateOnEnterRecents(0);
280 setVisibility(View.VISIBLE);
281 }
282 });
283 } else {
284 // Animate the tasks down behind the full screenshot
285 animate()
286 .scaleX(transform.scale)
287 .scaleY(transform.scale)
288 .translationY(transform.translationY)
289 .setStartDelay(0)
290 .setInterpolator(mConfig.linearOutSlowInInterpolator)
291 .setDuration(475)
292 .withLayer()
293 .start();
294 }
295
296 } else if (mConfig.launchedFromAppWithThumbnail) {
297 if (ctx.isFrontMost) {
298 // Animate the task bar of the first task view
Winson Chunga26fb782014-06-12 17:52:39 -0700299 mBarView.animateOnEnterRecents(mConfig.taskBarEnterAnimDelay);
300 // Animate the dim into view as well
301 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", getDimOverlayFromScale());
302 anim.setStartDelay(mConfig.taskBarEnterAnimDelay);
303 anim.setDuration(mConfig.taskBarEnterAnimDuration);
304 anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
305 anim.start();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700306 }
307
308 } else if (mConfig.launchedFromHome) {
309 // Animate the tasks up
310 int frontIndex = (ctx.stackViewCount - ctx.stackViewIndex - 1);
311 int delay = mConfig.taskBarEnterAnimDelay +
312 frontIndex * mConfig.taskViewEnterFromHomeDelay;
313 animate()
314 .scaleX(transform.scale)
315 .scaleY(transform.scale)
316 .translationY(transform.translationY)
317 .setStartDelay(delay)
318 .setInterpolator(mConfig.quintOutInterpolator)
319 .setDuration(mConfig.taskViewEnterFromHomeDuration)
320 .withLayer()
321 .start();
322 }
323 }
324
325 /** Animates this task view as it leaves recents */
326 public void animateOnExitRecents(ViewAnimation.TaskViewExitContext ctx) {
327 animate()
328 .translationY(ctx.offscreenTranslationY)
329 .setStartDelay(0)
330 .setInterpolator(mConfig.fastOutSlowInInterpolator)
331 .setDuration(mConfig.taskViewEnterFromHomeDuration)
Winson Chung37c8d8e2014-03-24 14:53:07 -0700332 .withLayer()
Winson Chungd42a6cf2014-06-03 16:24:04 -0700333 .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
Winson Chung37c8d8e2014-03-24 14:53:07 -0700334 .start();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700335 ctx.postAnimationTrigger.increment();
Winson Chung303e1ff2014-03-07 15:06:19 -0800336 }
337
Winson Chunga26fb782014-06-12 17:52:39 -0700338 /** Animates this task view if the user does not interact with the stack after a certain time. */
339 public void animateOnNoUserInteraction() {
340 mBarView.animateOnNoUserInteraction();
341 }
342
343 /** Mark this task view that the user does has not interacted with the stack after a certain time. */
344 public void setOnNoUserInteraction() {
345 mBarView.setOnNoUserInteraction();
346 }
347
Winson Chung303e1ff2014-03-07 15:06:19 -0800348 /** Animates this task view as it exits recents */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700349 public void animateOnLaunchingTask(final Runnable r) {
350 mBarView.animateOnLaunchingTask(r);
Winson Chunga26fb782014-06-12 17:52:39 -0700351
352 // Animate the dim
353 if (mDim > 0) {
354 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
355 anim.setDuration(mConfig.taskBarExitAnimDuration);
356 anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
357 anim.start();
358 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800359 }
360
Winson Chung9f49df92014-05-07 18:08:34 -0700361 /** Animates the deletion of this task view */
362 public void animateRemoval(final Runnable r) {
Winson Chung5a9b0b02014-05-20 17:32:03 -0700363 // Disabling clipping with the stack while the view is animating away
364 setClipViewInStack(false);
365
Winson Chungd42a6cf2014-06-03 16:24:04 -0700366 animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
Winson Chung9f49df92014-05-07 18:08:34 -0700367 .alpha(0f)
368 .setStartDelay(0)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700369 .setInterpolator(mConfig.fastOutSlowInInterpolator)
370 .setDuration(mConfig.taskViewRemoveAnimDuration)
Winson Chung9f49df92014-05-07 18:08:34 -0700371 .withLayer()
372 .withEndAction(new Runnable() {
373 @Override
374 public void run() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700375 // We just throw this into a runnable because starting a view property
376 // animation using layers can cause inconsisten results if we try and
377 // update the layers while the animation is running. In some cases,
378 // the runnabled passed in may start an animation which also uses layers
379 // so we defer all this by posting this.
380 r.run();
Winson Chung5a9b0b02014-05-20 17:32:03 -0700381
382 // Re-enable clipping with the stack (we will reuse this view)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700383 setClipViewInStack(true);
Winson Chung9f49df92014-05-07 18:08:34 -0700384 }
385 })
386 .start();
387 }
388
Winson Chung303e1ff2014-03-07 15:06:19 -0800389 /** Returns the rect we want to clip (it may not be the full rect) */
Winson Chung0d767552014-04-09 14:33:23 -0700390 Rect getClippingRect(Rect outRect) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800391 getHitRect(outRect);
392 // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
393 outRect.right = outRect.left + mThumbnailView.getRight();
394 outRect.bottom = outRect.top + mThumbnailView.getBottom();
Winson Chung303e1ff2014-03-07 15:06:19 -0800395 return outRect;
396 }
397
398 /** Enable the hw layers on this task view */
399 void enableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800400 mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700401 mBarView.enableHwLayers();
Winson Chung303e1ff2014-03-07 15:06:19 -0800402 }
403
404 /** Disable the hw layers on this task view */
405 void disableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800406 mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700407 mBarView.disableHwLayers();
Winson Chung303e1ff2014-03-07 15:06:19 -0800408 }
409
Winson Chung5a9b0b02014-05-20 17:32:03 -0700410 /**
411 * Returns whether this view should be clipped, or any views below should clip against this
412 * view.
413 */
414 boolean shouldClipViewInStack() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700415 return mClipViewInStack && (getVisibility() == View.VISIBLE);
Winson Chung5a9b0b02014-05-20 17:32:03 -0700416 }
417
418 /** Sets whether this view should be clipped, or clipped against. */
419 void setClipViewInStack(boolean clip) {
420 if (clip != mClipViewInStack) {
421 mClipViewInStack = clip;
422 if (getParent() instanceof View) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700423 getHitRect(mTmpRect);
424 ((View) getParent()).invalidate(mTmpRect);
Winson Chung5a9b0b02014-05-20 17:32:03 -0700425 }
426 }
427 }
428
Winson Chunga26fb782014-06-12 17:52:39 -0700429 /** Returns the current dim. */
430 public void setDim(int dim) {
431 mDim = dim;
432 postInvalidateOnAnimation();
433 }
434
435 /** Returns the current dim. */
436 public int getDim() {
437 return mDim;
438 }
439
440 /** Compute the dim as a function of the scale of this view. */
441 int getDimOverlayFromScale() {
Winson Chung14926462014-04-14 18:57:14 -0700442 float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
443 float scaleRange = 1f - minScale;
444 float dim = (1f - getScaleX()) / scaleRange;
445 dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
Winson Chunga26fb782014-06-12 17:52:39 -0700446 return Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
447 }
448
449 /** Update the dim as a function of the scale of this view. */
450 void updateDimOverlayFromScale() {
451 setDim(getDimOverlayFromScale());
Winson Chung14926462014-04-14 18:57:14 -0700452 }
453
454 @Override
455 public void draw(Canvas canvas) {
456 // Apply the rounded rect clip path on the whole view
457 canvas.clipPath(mRoundedRectClipPath);
458
459 super.draw(canvas);
460
461 // Apply the dim if necessary
462 if (mDim > 0) {
463 canvas.drawColor(mDim << 24);
464 }
465 }
466
Winson Chung1e8d71b2014-05-16 17:05:22 -0700467 /**
468 * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
469 * if the view is not currently visible, or we are in touch state (where we still want to keep
470 * track of focus).
471 */
472 public void setFocusedTask() {
473 mIsFocused = true;
474 requestFocus();
Winson Chung47a3e652014-05-21 16:03:42 -0700475 invalidate();
476 mCb.onTaskFocused(this);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700477 }
478
479 /**
480 * Updates the explicitly focused state when the view focus changes.
481 */
482 @Override
483 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
484 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
485 if (!gainFocus) {
486 mIsFocused = false;
Winson Chung47a3e652014-05-21 16:03:42 -0700487 invalidate();
Winson Chung1e8d71b2014-05-16 17:05:22 -0700488 }
489 }
490
491 /**
492 * Returns whether we have explicitly been focused.
493 */
494 public boolean isFocusedTask() {
495 return mIsFocused || isFocused();
496 }
497
Winson Chung4d7b0922014-03-13 17:14:17 -0700498 /**** TaskCallbacks Implementation ****/
499
Winson Chung04dfe0d2014-03-14 14:06:29 -0700500 /** Binds this task view to the task */
501 public void onTaskBound(Task t) {
502 mTask = t;
503 mTask.setCallbacks(this);
Winson Chung303e1ff2014-03-07 15:06:19 -0800504 }
505
506 @Override
Winson Chung4c71aef2014-03-21 15:15:11 -0700507 public void onTaskDataLoaded(boolean reloadingTaskData) {
Winson Chung863db8a2014-05-20 14:27:39 -0700508 if (mThumbnailView != null && mBarView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700509 // Bind each of the views to the new task data
510 mThumbnailView.rebindToTask(mTask, reloadingTaskData);
511 mBarView.rebindToTask(mTask, reloadingTaskData);
Winson Chung9f9679d2014-04-11 16:49:09 -0700512 // Rebind any listeners
513 mBarView.mApplicationIcon.setOnClickListener(this);
Winson Chung54e297a2014-05-09 17:15:32 -0700514 mBarView.mDismissButton.setOnClickListener(this);
Winson Chung6cb485f2014-05-19 10:30:43 -0700515 if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700516 if (mConfig.developerOptionsEnabled) {
Winson Chung6cb485f2014-05-19 10:30:43 -0700517 mBarView.mApplicationIcon.setOnLongClickListener(this);
518 }
519 }
Winson Chung37c8d8e2014-03-24 14:53:07 -0700520 }
521 mTaskDataLoaded = true;
Winson Chung4d7b0922014-03-13 17:14:17 -0700522 }
523
524 @Override
Winson Chung04dfe0d2014-03-14 14:06:29 -0700525 public void onTaskDataUnloaded() {
Winson Chung863db8a2014-05-20 14:27:39 -0700526 if (mThumbnailView != null && mBarView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700527 // Unbind each of the views from the task data and remove the task callback
528 mTask.setCallbacks(null);
529 mThumbnailView.unbindFromTask();
530 mBarView.unbindFromTask();
Winson Chung9f9679d2014-04-11 16:49:09 -0700531 // Unbind any listeners
532 mBarView.mApplicationIcon.setOnClickListener(null);
Winson Chung6cb485f2014-05-19 10:30:43 -0700533 mBarView.mDismissButton.setOnClickListener(null);
534 if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
535 mBarView.mApplicationIcon.setOnLongClickListener(null);
536 }
Winson Chung37c8d8e2014-03-24 14:53:07 -0700537 }
538 mTaskDataLoaded = false;
Winson Chung4d7b0922014-03-13 17:14:17 -0700539 }
540
541 @Override
Winson Chung303e1ff2014-03-07 15:06:19 -0800542 public void onClick(View v) {
Winson Chung863db8a2014-05-20 14:27:39 -0700543 if (v == mBarView.mApplicationIcon) {
Winson Chung9f9679d2014-04-11 16:49:09 -0700544 mCb.onTaskIconClicked(this);
Winson Chung54e297a2014-05-09 17:15:32 -0700545 } else if (v == mBarView.mDismissButton) {
546 // Animate out the view and call the callback
547 final TaskView tv = this;
548 animateRemoval(new Runnable() {
549 @Override
550 public void run() {
551 mCb.onTaskDismissed(tv);
552 }
553 });
Winson Chung9f9679d2014-04-11 16:49:09 -0700554 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800555 }
Winson Chung6cb485f2014-05-19 10:30:43 -0700556
557 @Override
558 public boolean onLongClick(View v) {
559 if (v == mBarView.mApplicationIcon) {
560 mCb.onTaskAppInfoClicked(this);
561 return true;
562 }
563 return false;
564 }
Winson Chung7bb18852014-05-20 23:25:41 +0000565}