blob: 9e4386f4f56f1059b0ef2ee19856b87974690aaf [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 Chung14926462014-04-14 18:57:14 -070019import android.animation.TimeInterpolator;
20import android.animation.ValueAnimator;
Winson Chung303e1ff2014-03-07 15:06:19 -080021import android.content.Context;
Winson Chung14926462014-04-14 18:57:14 -070022import android.graphics.Canvas;
Winson Chung96e3bc12014-05-06 16:44:12 -070023import android.graphics.Outline;
Winson Chung14926462014-04-14 18:57:14 -070024import android.graphics.Path;
Winson Chung9f9679d2014-04-11 16:49:09 -070025import android.graphics.Point;
Winson Chung303e1ff2014-03-07 15:06:19 -080026import android.graphics.Rect;
Winson Chung14926462014-04-14 18:57:14 -070027import android.graphics.RectF;
Winson Chung37c8d8e2014-03-24 14:53:07 -070028import android.util.AttributeSet;
Winson Chung9f9679d2014-04-11 16:49:09 -070029import android.view.MotionEvent;
Winson Chung303e1ff2014-03-07 15:06:19 -080030import android.view.View;
Winson Chungd42a6cf2014-06-03 16:24:04 -070031import android.view.ViewParent;
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 };
78
Winson Chung37c8d8e2014-03-24 14:53:07 -070079
80 public TaskView(Context context) {
81 this(context, null);
Winson Chung303e1ff2014-03-07 15:06:19 -080082 }
83
Winson Chung37c8d8e2014-03-24 14:53:07 -070084 public TaskView(Context context, AttributeSet attrs) {
85 this(context, attrs, 0);
86 }
Winson Chung303e1ff2014-03-07 15:06:19 -080087
Winson Chung37c8d8e2014-03-24 14:53:07 -070088 public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
89 this(context, attrs, defStyleAttr, 0);
90 }
91
92 public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
93 super(context, attrs, defStyleAttr, defStyleRes);
Winson Chungd42a6cf2014-06-03 16:24:04 -070094 mConfig = RecentsConfiguration.getInstance();
Winson Chung14926462014-04-14 18:57:14 -070095 setWillNotDraw(false);
Winson Chung37c8d8e2014-03-24 14:53:07 -070096 }
97
98 @Override
99 protected void onFinishInflate() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700100 mMaxDim = mConfig.taskStackMaxDim;
Winson Chung14926462014-04-14 18:57:14 -0700101
Winson Chung5a9b0b02014-05-20 17:32:03 -0700102 // By default, all views are clipped to other views in their stack
103 mClipViewInStack = true;
104
Winson Chung37c8d8e2014-03-24 14:53:07 -0700105 // Bind the views
106 mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
107 mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
Winson Chung9f9679d2014-04-11 16:49:09 -0700108
Winson Chung37c8d8e2014-03-24 14:53:07 -0700109 if (mTaskDataLoaded) {
110 onTaskDataLoaded(false);
Winson Chung303e1ff2014-03-07 15:06:19 -0800111 }
112 }
113
Winson Chung9f9679d2014-04-11 16:49:09 -0700114 @Override
Winson Chung14926462014-04-14 18:57:14 -0700115 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
116 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
117
118 // Update the rounded rect clip path
Winson Chungd42a6cf2014-06-03 16:24:04 -0700119 float radius = mConfig.taskViewRoundedCornerRadiusPx;
Winson Chung14926462014-04-14 18:57:14 -0700120 mRoundedRectClipPath.reset();
121 mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
122 radius, radius, Path.Direction.CW);
Winson Chung96e3bc12014-05-06 16:44:12 -0700123
124 // Update the outline
125 Outline o = new Outline();
Winson Chung602de032014-05-27 12:19:28 -0700126 o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight() -
Winson Chungd42a6cf2014-06-03 16:24:04 -0700127 mConfig.taskViewShadowOutlineBottomInsetPx, radius);
Winson Chung96e3bc12014-05-06 16:44:12 -0700128 setOutline(o);
Winson Chung14926462014-04-14 18:57:14 -0700129 }
130
131 @Override
Winson Chung9f9679d2014-04-11 16:49:09 -0700132 public boolean onInterceptTouchEvent(MotionEvent ev) {
133 switch (ev.getAction()) {
134 case MotionEvent.ACTION_DOWN:
135 case MotionEvent.ACTION_MOVE:
136 mLastTouchDown.set((int) ev.getX(), (int) ev.getY());
137 break;
138 }
139 return super.onInterceptTouchEvent(ev);
140 }
141
Winson Chung04dfe0d2014-03-14 14:06:29 -0700142 /** Set callback */
143 void setCallbacks(TaskViewCallbacks cb) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800144 mCb = cb;
145 }
146
Winson Chung303e1ff2014-03-07 15:06:19 -0800147 /** Gets the task */
148 Task getTask() {
149 return mTask;
150 }
151
152 /** Synchronizes this view's properties with the task's transform */
Winson Chungc6a16232014-04-01 14:04:48 -0700153 void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
154 TaskViewTransform toTransform, int duration) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700155 if (Console.Enabled) {
156 Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]",
157 "duration: " + duration, Console.AnsiPurple);
158 }
Winson Chung96e3bc12014-05-06 16:44:12 -0700159
Winson Chung54e297a2014-05-09 17:15:32 -0700160 // Update the bar view
161 mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
162
163 // Update this task view
Winson Chung303e1ff2014-03-07 15:06:19 -0800164 if (duration > 0) {
165 if (animateFromTransform != null) {
166 setTranslationY(animateFromTransform.translationY);
Winson Chung814086d2014-05-07 15:01:14 -0700167 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700168 setTranslationZ(animateFromTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700169 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800170 setScaleX(animateFromTransform.scale);
171 setScaleY(animateFromTransform.scale);
Winson Chungc6a16232014-04-01 14:04:48 -0700172 setAlpha(animateFromTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800173 }
Winson Chung814086d2014-05-07 15:01:14 -0700174 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700175 animate().translationZ(toTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700176 }
Winson Chungc6a16232014-04-01 14:04:48 -0700177 animate().translationY(toTransform.translationY)
178 .scaleX(toTransform.scale)
179 .scaleY(toTransform.scale)
180 .alpha(toTransform.alpha)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700181 .setStartDelay(0)
Winson Chung303e1ff2014-03-07 15:06:19 -0800182 .setDuration(duration)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700183 .setInterpolator(mConfig.fastOutSlowInInterpolator)
184 .setUpdateListener(mUpdateDimListener)
Winson Chung303e1ff2014-03-07 15:06:19 -0800185 .start();
186 } else {
Winson Chungc6a16232014-04-01 14:04:48 -0700187 setTranslationY(toTransform.translationY);
Winson Chung814086d2014-05-07 15:01:14 -0700188 if (Constants.DebugFlags.App.EnableShadows) {
Winson Chungb13c46e2014-06-09 18:33:08 -0700189 setTranslationZ(toTransform.translationZ);
Winson Chung814086d2014-05-07 15:01:14 -0700190 }
Winson Chungc6a16232014-04-01 14:04:48 -0700191 setScaleX(toTransform.scale);
192 setScaleY(toTransform.scale);
193 setAlpha(toTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800194 }
Winson Chung14926462014-04-14 18:57:14 -0700195 updateDimOverlayFromScale();
196 invalidate();
Winson Chung303e1ff2014-03-07 15:06:19 -0800197 }
198
199 /** Resets this view's properties */
200 void resetViewProperties() {
201 setTranslationX(0f);
202 setTranslationY(0f);
Winson Chung814086d2014-05-07 15:01:14 -0700203 if (Constants.DebugFlags.App.EnableShadows) {
204 setTranslationZ(0f);
205 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800206 setScaleX(1f);
207 setScaleY(1f);
208 setAlpha(1f);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700209 mDim = 0;
Winson Chung14926462014-04-14 18:57:14 -0700210 invalidate();
Winson Chung303e1ff2014-03-07 15:06:19 -0800211 }
212
Winson Chung11ca76a52014-04-10 17:29:13 -0700213 /**
214 * When we are un/filtering, this method will set up the transform that we are animating to,
215 * in order to hide the task.
216 */
Winson Chungc6a16232014-04-01 14:04:48 -0700217 void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
218 // Fade the view out and slide it away
219 toTransform.alpha = 0f;
220 toTransform.translationY += 200;
221 }
222
Winson Chung11ca76a52014-04-10 17:29:13 -0700223 /**
224 * When we are un/filtering, this method will setup the transform that we are animating from,
225 * in order to show the task.
226 */
Winson Chungc6a16232014-04-01 14:04:48 -0700227 void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
228 // Fade the view in
229 fromTransform.alpha = 0f;
230 }
231
Winson Chung24cf1522014-05-29 12:03:33 -0700232 /** Prepares this task view for the enter-recents animations. This is called earlier in the
233 * first layout because the actual animation into recents may take a long time. */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700234 public void prepareAnimateEnterRecents(boolean isTaskViewFrontMost, int offsetY, int offscreenY,
235 Rect taskRect) {
236 if (mConfig.launchedFromAppWithScreenshot) {
237 if (isTaskViewFrontMost) {
238 // Hide the task view as we are going to animate the full screenshot into view
239 // and then replace it with this view once we are done
240 setVisibility(View.INVISIBLE);
241 // Also hide the front most task bar view so we can animate it in
242 mBarView.prepareAnimateEnterRecents();
243 } else {
244 // Top align the task views
245 setTranslationY(offsetY);
246 setScaleX(1f);
247 setScaleY(1f);
248 }
249
250 } else if (mConfig.launchedFromAppWithThumbnail) {
251 if (isTaskViewFrontMost) {
252 // Hide the front most task bar view so we can animate it in
253 mBarView.prepareAnimateEnterRecents();
254 }
255
256 } else if (mConfig.launchedFromHome) {
257 // Move the task view off screen (below) so we can animate it in
258 setTranslationY(offscreenY);
259 setScaleX(1f);
260 setScaleY(1f);
261 }
Winson Chung24cf1522014-05-29 12:03:33 -0700262 }
263
Winson Chung303e1ff2014-03-07 15:06:19 -0800264 /** Animates this task view as it enters recents */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700265 public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx) {
266 TaskViewTransform transform = ctx.transform;
267
268 if (mConfig.launchedFromAppWithScreenshot) {
269 if (ctx.isFrontMost) {
270 // Animate the full screenshot down first, before swapping with this task view
271 ctx.fullScreenshot.animateOnEnterRecents(ctx, new Runnable() {
272 @Override
273 public void run() {
274 // Animate the task bar of the first task view
275 mBarView.animateOnEnterRecents(0);
276 setVisibility(View.VISIBLE);
277 }
278 });
279 } else {
280 // Animate the tasks down behind the full screenshot
281 animate()
282 .scaleX(transform.scale)
283 .scaleY(transform.scale)
284 .translationY(transform.translationY)
285 .setStartDelay(0)
286 .setInterpolator(mConfig.linearOutSlowInInterpolator)
287 .setDuration(475)
288 .withLayer()
289 .start();
290 }
291
292 } else if (mConfig.launchedFromAppWithThumbnail) {
293 if (ctx.isFrontMost) {
294 // Animate the task bar of the first task view
295 mBarView.animateOnEnterRecents(-1);
296 }
297
298 } else if (mConfig.launchedFromHome) {
299 // Animate the tasks up
300 int frontIndex = (ctx.stackViewCount - ctx.stackViewIndex - 1);
301 int delay = mConfig.taskBarEnterAnimDelay +
302 frontIndex * mConfig.taskViewEnterFromHomeDelay;
303 animate()
304 .scaleX(transform.scale)
305 .scaleY(transform.scale)
306 .translationY(transform.translationY)
307 .setStartDelay(delay)
308 .setInterpolator(mConfig.quintOutInterpolator)
309 .setDuration(mConfig.taskViewEnterFromHomeDuration)
310 .withLayer()
311 .start();
312 }
313 }
314
315 /** Animates this task view as it leaves recents */
316 public void animateOnExitRecents(ViewAnimation.TaskViewExitContext ctx) {
317 animate()
318 .translationY(ctx.offscreenTranslationY)
319 .setStartDelay(0)
320 .setInterpolator(mConfig.fastOutSlowInInterpolator)
321 .setDuration(mConfig.taskViewEnterFromHomeDuration)
Winson Chung37c8d8e2014-03-24 14:53:07 -0700322 .withLayer()
Winson Chungd42a6cf2014-06-03 16:24:04 -0700323 .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
Winson Chung37c8d8e2014-03-24 14:53:07 -0700324 .start();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700325 ctx.postAnimationTrigger.increment();
Winson Chung303e1ff2014-03-07 15:06:19 -0800326 }
327
328 /** Animates this task view as it exits recents */
Winson Chungd42a6cf2014-06-03 16:24:04 -0700329 public void animateOnLaunchingTask(final Runnable r) {
330 mBarView.animateOnLaunchingTask(r);
Winson Chung303e1ff2014-03-07 15:06:19 -0800331 }
332
Winson Chung9f49df92014-05-07 18:08:34 -0700333 /** Animates the deletion of this task view */
334 public void animateRemoval(final Runnable r) {
Winson Chung5a9b0b02014-05-20 17:32:03 -0700335 // Disabling clipping with the stack while the view is animating away
336 setClipViewInStack(false);
337
Winson Chungd42a6cf2014-06-03 16:24:04 -0700338 animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
Winson Chung9f49df92014-05-07 18:08:34 -0700339 .alpha(0f)
340 .setStartDelay(0)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700341 .setInterpolator(mConfig.fastOutSlowInInterpolator)
342 .setDuration(mConfig.taskViewRemoveAnimDuration)
Winson Chung9f49df92014-05-07 18:08:34 -0700343 .withLayer()
344 .withEndAction(new Runnable() {
345 @Override
346 public void run() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700347 // We just throw this into a runnable because starting a view property
348 // animation using layers can cause inconsisten results if we try and
349 // update the layers while the animation is running. In some cases,
350 // the runnabled passed in may start an animation which also uses layers
351 // so we defer all this by posting this.
352 r.run();
Winson Chung5a9b0b02014-05-20 17:32:03 -0700353
354 // Re-enable clipping with the stack (we will reuse this view)
Winson Chungd42a6cf2014-06-03 16:24:04 -0700355 setClipViewInStack(true);
Winson Chung9f49df92014-05-07 18:08:34 -0700356 }
357 })
358 .start();
359 }
360
Winson Chung303e1ff2014-03-07 15:06:19 -0800361 /** Returns the rect we want to clip (it may not be the full rect) */
Winson Chung0d767552014-04-09 14:33:23 -0700362 Rect getClippingRect(Rect outRect) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800363 getHitRect(outRect);
364 // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
365 outRect.right = outRect.left + mThumbnailView.getRight();
366 outRect.bottom = outRect.top + mThumbnailView.getBottom();
Winson Chung303e1ff2014-03-07 15:06:19 -0800367 return outRect;
368 }
369
370 /** Enable the hw layers on this task view */
371 void enableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800372 mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700373 mBarView.enableHwLayers();
Winson Chung303e1ff2014-03-07 15:06:19 -0800374 }
375
376 /** Disable the hw layers on this task view */
377 void disableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800378 mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700379 mBarView.disableHwLayers();
Winson Chung303e1ff2014-03-07 15:06:19 -0800380 }
381
Winson Chung5a9b0b02014-05-20 17:32:03 -0700382 /**
383 * Returns whether this view should be clipped, or any views below should clip against this
384 * view.
385 */
386 boolean shouldClipViewInStack() {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700387 return mClipViewInStack && (getVisibility() == View.VISIBLE);
Winson Chung5a9b0b02014-05-20 17:32:03 -0700388 }
389
390 /** Sets whether this view should be clipped, or clipped against. */
391 void setClipViewInStack(boolean clip) {
392 if (clip != mClipViewInStack) {
393 mClipViewInStack = clip;
394 if (getParent() instanceof View) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700395 getHitRect(mTmpRect);
396 ((View) getParent()).invalidate(mTmpRect);
Winson Chung5a9b0b02014-05-20 17:32:03 -0700397 }
398 }
399 }
400
Winson Chung14926462014-04-14 18:57:14 -0700401 /** Update the dim as a function of the scale of this view. */
402 void updateDimOverlayFromScale() {
403 float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
404 float scaleRange = 1f - minScale;
405 float dim = (1f - getScaleX()) / scaleRange;
406 dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
407 mDim = Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
Winson Chung14926462014-04-14 18:57:14 -0700408 }
409
410 @Override
411 public void draw(Canvas canvas) {
412 // Apply the rounded rect clip path on the whole view
413 canvas.clipPath(mRoundedRectClipPath);
414
415 super.draw(canvas);
416
417 // Apply the dim if necessary
418 if (mDim > 0) {
419 canvas.drawColor(mDim << 24);
420 }
421 }
422
Winson Chung1e8d71b2014-05-16 17:05:22 -0700423 /**
424 * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
425 * if the view is not currently visible, or we are in touch state (where we still want to keep
426 * track of focus).
427 */
428 public void setFocusedTask() {
429 mIsFocused = true;
430 requestFocus();
Winson Chung47a3e652014-05-21 16:03:42 -0700431 invalidate();
432 mCb.onTaskFocused(this);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700433 }
434
435 /**
436 * Updates the explicitly focused state when the view focus changes.
437 */
438 @Override
439 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
440 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
441 if (!gainFocus) {
442 mIsFocused = false;
Winson Chung47a3e652014-05-21 16:03:42 -0700443 invalidate();
Winson Chung1e8d71b2014-05-16 17:05:22 -0700444 }
445 }
446
447 /**
448 * Returns whether we have explicitly been focused.
449 */
450 public boolean isFocusedTask() {
451 return mIsFocused || isFocused();
452 }
453
Winson Chung4d7b0922014-03-13 17:14:17 -0700454 /**** TaskCallbacks Implementation ****/
455
Winson Chung04dfe0d2014-03-14 14:06:29 -0700456 /** Binds this task view to the task */
457 public void onTaskBound(Task t) {
458 mTask = t;
459 mTask.setCallbacks(this);
Winson Chung303e1ff2014-03-07 15:06:19 -0800460 }
461
462 @Override
Winson Chung4c71aef2014-03-21 15:15:11 -0700463 public void onTaskDataLoaded(boolean reloadingTaskData) {
Winson Chung863db8a2014-05-20 14:27:39 -0700464 if (mThumbnailView != null && mBarView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700465 // Bind each of the views to the new task data
466 mThumbnailView.rebindToTask(mTask, reloadingTaskData);
467 mBarView.rebindToTask(mTask, reloadingTaskData);
Winson Chung9f9679d2014-04-11 16:49:09 -0700468 // Rebind any listeners
469 mBarView.mApplicationIcon.setOnClickListener(this);
Winson Chung54e297a2014-05-09 17:15:32 -0700470 mBarView.mDismissButton.setOnClickListener(this);
Winson Chung6cb485f2014-05-19 10:30:43 -0700471 if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
Winson Chungd42a6cf2014-06-03 16:24:04 -0700472 if (mConfig.developerOptionsEnabled) {
Winson Chung6cb485f2014-05-19 10:30:43 -0700473 mBarView.mApplicationIcon.setOnLongClickListener(this);
474 }
475 }
Winson Chung37c8d8e2014-03-24 14:53:07 -0700476 }
477 mTaskDataLoaded = true;
Winson Chung4d7b0922014-03-13 17:14:17 -0700478 }
479
480 @Override
Winson Chung04dfe0d2014-03-14 14:06:29 -0700481 public void onTaskDataUnloaded() {
Winson Chung863db8a2014-05-20 14:27:39 -0700482 if (mThumbnailView != null && mBarView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700483 // Unbind each of the views from the task data and remove the task callback
484 mTask.setCallbacks(null);
485 mThumbnailView.unbindFromTask();
486 mBarView.unbindFromTask();
Winson Chung9f9679d2014-04-11 16:49:09 -0700487 // Unbind any listeners
488 mBarView.mApplicationIcon.setOnClickListener(null);
Winson Chung6cb485f2014-05-19 10:30:43 -0700489 mBarView.mDismissButton.setOnClickListener(null);
490 if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
491 mBarView.mApplicationIcon.setOnLongClickListener(null);
492 }
Winson Chung37c8d8e2014-03-24 14:53:07 -0700493 }
494 mTaskDataLoaded = false;
Winson Chung4d7b0922014-03-13 17:14:17 -0700495 }
496
497 @Override
Winson Chung303e1ff2014-03-07 15:06:19 -0800498 public void onClick(View v) {
Winson Chung863db8a2014-05-20 14:27:39 -0700499 if (v == mBarView.mApplicationIcon) {
Winson Chung9f9679d2014-04-11 16:49:09 -0700500 mCb.onTaskIconClicked(this);
Winson Chung54e297a2014-05-09 17:15:32 -0700501 } else if (v == mBarView.mDismissButton) {
502 // Animate out the view and call the callback
503 final TaskView tv = this;
504 animateRemoval(new Runnable() {
505 @Override
506 public void run() {
507 mCb.onTaskDismissed(tv);
508 }
509 });
Winson Chung9f9679d2014-04-11 16:49:09 -0700510 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800511 }
Winson Chung6cb485f2014-05-19 10:30:43 -0700512
513 @Override
514 public boolean onLongClick(View v) {
515 if (v == mBarView.mApplicationIcon) {
516 mCb.onTaskAppInfoClicked(this);
517 return true;
518 }
519 return false;
520 }
Winson Chung7bb18852014-05-20 23:25:41 +0000521}