blob: 81805d59b116b0a465cc4638ef7aa750c6caec2f [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 Chung303e1ff2014-03-07 15:06:19 -080019import android.content.Context;
Winson Chung9f9679d2014-04-11 16:49:09 -070020import android.graphics.Point;
Winson Chung303e1ff2014-03-07 15:06:19 -080021import android.graphics.Rect;
Winson Chung37c8d8e2014-03-24 14:53:07 -070022import android.util.AttributeSet;
Winson Chung9f9679d2014-04-11 16:49:09 -070023import android.view.MotionEvent;
Winson Chung303e1ff2014-03-07 15:06:19 -080024import android.view.View;
Winson Chung303e1ff2014-03-07 15:06:19 -080025import android.widget.FrameLayout;
Winson Chung37c8d8e2014-03-24 14:53:07 -070026import com.android.systemui.R;
Winson Chung2f2ca082014-04-03 18:05:29 -070027import com.android.systemui.recents.BakedBezierInterpolator;
Winson Chung303e1ff2014-03-07 15:06:19 -080028import com.android.systemui.recents.RecentsConfiguration;
Winson Chung2f2ca082014-04-03 18:05:29 -070029import com.android.systemui.recents.Utilities;
Winson Chung303e1ff2014-03-07 15:06:19 -080030import com.android.systemui.recents.model.Task;
Winson Chung303e1ff2014-03-07 15:06:19 -080031
Winson Chung303e1ff2014-03-07 15:06:19 -080032
Winson Chung37c8d8e2014-03-24 14:53:07 -070033/* A task view */
Winson Chung9f9679d2014-04-11 16:49:09 -070034public class TaskView extends FrameLayout implements View.OnClickListener,
35 Task.TaskCallbacks {
Winson Chung37c8d8e2014-03-24 14:53:07 -070036 /** The TaskView callbacks */
37 interface TaskViewCallbacks {
38 public void onTaskIconClicked(TaskView tv);
Winson Chung9f9679d2014-04-11 16:49:09 -070039 public void onTaskInfoPanelShown(TaskView tv);
40 public void onTaskInfoPanelHidden(TaskView tv);
41 public void onTaskAppInfoClicked(TaskView tv);
42
Winson Chung37c8d8e2014-03-24 14:53:07 -070043 // 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;
Winson Chung9f9679d2014-04-11 16:49:09 -070048 boolean mTaskInfoPaneVisible;
49 Point mLastTouchDown = new Point();
Winson Chung37c8d8e2014-03-24 14:53:07 -070050
51 TaskThumbnailView mThumbnailView;
52 TaskBarView mBarView;
Winson Chung9f9679d2014-04-11 16:49:09 -070053 TaskInfoView mInfoView;
Winson Chung37c8d8e2014-03-24 14:53:07 -070054 TaskViewCallbacks mCb;
Winson Chung303e1ff2014-03-07 15:06:19 -080055
Winson Chung37c8d8e2014-03-24 14:53:07 -070056
57 public TaskView(Context context) {
58 this(context, null);
Winson Chung303e1ff2014-03-07 15:06:19 -080059 }
60
Winson Chung37c8d8e2014-03-24 14:53:07 -070061 public TaskView(Context context, AttributeSet attrs) {
62 this(context, attrs, 0);
63 }
Winson Chung303e1ff2014-03-07 15:06:19 -080064
Winson Chung37c8d8e2014-03-24 14:53:07 -070065 public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
66 this(context, attrs, defStyleAttr, 0);
67 }
68
69 public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
70 super(context, attrs, defStyleAttr, defStyleRes);
Winson Chung37c8d8e2014-03-24 14:53:07 -070071 }
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 Chung9f9679d2014-04-11 16:49:09 -070078 mInfoView = (TaskInfoView) findViewById(R.id.task_view_info_pane);
79
Winson Chung37c8d8e2014-03-24 14:53:07 -070080 if (mTaskDataLoaded) {
81 onTaskDataLoaded(false);
Winson Chung303e1ff2014-03-07 15:06:19 -080082 }
83 }
84
Winson Chung9f9679d2014-04-11 16:49:09 -070085 @Override
86 public boolean onInterceptTouchEvent(MotionEvent ev) {
87 switch (ev.getAction()) {
88 case MotionEvent.ACTION_DOWN:
89 case MotionEvent.ACTION_MOVE:
90 mLastTouchDown.set((int) ev.getX(), (int) ev.getY());
91 break;
92 }
93 return super.onInterceptTouchEvent(ev);
94 }
95
Winson Chung04dfe0d2014-03-14 14:06:29 -070096 /** Set callback */
97 void setCallbacks(TaskViewCallbacks cb) {
Winson Chung303e1ff2014-03-07 15:06:19 -080098 mCb = cb;
99 }
100
Winson Chung303e1ff2014-03-07 15:06:19 -0800101 /** Gets the task */
102 Task getTask() {
103 return mTask;
104 }
105
106 /** Synchronizes this view's properties with the task's transform */
Winson Chungc6a16232014-04-01 14:04:48 -0700107 void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
108 TaskViewTransform toTransform, int duration) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800109 if (duration > 0) {
110 if (animateFromTransform != null) {
111 setTranslationY(animateFromTransform.translationY);
112 setScaleX(animateFromTransform.scale);
113 setScaleY(animateFromTransform.scale);
Winson Chungc6a16232014-04-01 14:04:48 -0700114 setAlpha(animateFromTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800115 }
Winson Chungc6a16232014-04-01 14:04:48 -0700116 animate().translationY(toTransform.translationY)
117 .scaleX(toTransform.scale)
118 .scaleY(toTransform.scale)
119 .alpha(toTransform.alpha)
Winson Chung303e1ff2014-03-07 15:06:19 -0800120 .setDuration(duration)
Winson Chung2f2ca082014-04-03 18:05:29 -0700121 .setInterpolator(BakedBezierInterpolator.INSTANCE)
Winson Chungc6a16232014-04-01 14:04:48 -0700122 .withLayer()
Winson Chung303e1ff2014-03-07 15:06:19 -0800123 .start();
124 } else {
Winson Chungc6a16232014-04-01 14:04:48 -0700125 setTranslationY(toTransform.translationY);
126 setScaleX(toTransform.scale);
127 setScaleY(toTransform.scale);
128 setAlpha(toTransform.alpha);
Winson Chung303e1ff2014-03-07 15:06:19 -0800129 }
130 }
131
132 /** Resets this view's properties */
133 void resetViewProperties() {
134 setTranslationX(0f);
135 setTranslationY(0f);
136 setScaleX(1f);
137 setScaleY(1f);
138 setAlpha(1f);
139 }
140
Winson Chung11ca76a52014-04-10 17:29:13 -0700141 /**
142 * When we are un/filtering, this method will set up the transform that we are animating to,
143 * in order to hide the task.
144 */
Winson Chungc6a16232014-04-01 14:04:48 -0700145 void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
146 // Fade the view out and slide it away
147 toTransform.alpha = 0f;
148 toTransform.translationY += 200;
149 }
150
Winson Chung11ca76a52014-04-10 17:29:13 -0700151 /**
152 * When we are un/filtering, this method will setup the transform that we are animating from,
153 * in order to show the task.
154 */
Winson Chungc6a16232014-04-01 14:04:48 -0700155 void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
156 // Fade the view in
157 fromTransform.alpha = 0f;
158 }
159
Winson Chung303e1ff2014-03-07 15:06:19 -0800160 /** Animates this task view as it enters recents */
161 public void animateOnEnterRecents() {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700162 RecentsConfiguration config = RecentsConfiguration.getInstance();
163 int translate = config.pxFromDp(10);
164 mBarView.setScaleX(1.25f);
165 mBarView.setScaleY(1.25f);
166 mBarView.setAlpha(0f);
167 mBarView.setTranslationX(translate / 2);
168 mBarView.setTranslationY(-translate);
169 mBarView.animate()
170 .alpha(1f)
171 .scaleX(1f)
172 .scaleY(1f)
173 .translationX(0)
174 .translationY(0)
175 .setStartDelay(235)
Winson Chung2f2ca082014-04-03 18:05:29 -0700176 .setInterpolator(BakedBezierInterpolator.INSTANCE)
Winson Chung0d767552014-04-09 14:33:23 -0700177 .setDuration(config.taskBarEnterAnimDuration)
Winson Chung37c8d8e2014-03-24 14:53:07 -0700178 .withLayer()
179 .start();
Winson Chung303e1ff2014-03-07 15:06:19 -0800180 }
181
182 /** Animates this task view as it exits recents */
183 public void animateOnLeavingRecents(final Runnable r) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700184 RecentsConfiguration config = RecentsConfiguration.getInstance();
185 int translate = config.pxFromDp(10);
186 mBarView.animate()
187 .alpha(0f)
188 .scaleX(1.1f)
189 .scaleY(1.1f)
190 .translationX(translate / 2)
191 .translationY(-translate)
192 .setStartDelay(0)
Winson Chung2f2ca082014-04-03 18:05:29 -0700193 .setInterpolator(BakedBezierInterpolator.INSTANCE)
194 .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
Winson Chung37c8d8e2014-03-24 14:53:07 -0700195 .withLayer()
Winson Chung0d767552014-04-09 14:33:23 -0700196 .withEndAction(new Runnable() {
197 @Override
198 public void run() {
199 post(r);
200 }
201 })
Winson Chung37c8d8e2014-03-24 14:53:07 -0700202 .start();
Winson Chung303e1ff2014-03-07 15:06:19 -0800203 }
204
205 /** Returns the rect we want to clip (it may not be the full rect) */
Winson Chung0d767552014-04-09 14:33:23 -0700206 Rect getClippingRect(Rect outRect) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800207 getHitRect(outRect);
208 // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
209 outRect.right = outRect.left + mThumbnailView.getRight();
210 outRect.bottom = outRect.top + mThumbnailView.getBottom();
Winson Chung303e1ff2014-03-07 15:06:19 -0800211 return outRect;
212 }
213
Winson Chung9f9679d2014-04-11 16:49:09 -0700214 /** Returns whether this task has an info pane visible */
215 boolean isInfoPaneVisible() {
216 return mTaskInfoPaneVisible;
217 }
218
219 /** Shows the info pane if it is not visible. */
220 void showInfoPane(Rect taskVisibleRect) {
221 if (mTaskInfoPaneVisible) return;
222
223 // Remove the bar view from the visible rect and update the info pane contents
224 taskVisibleRect.top += mBarView.getMeasuredHeight();
225 mInfoView.updateContents(taskVisibleRect);
226
227 // Show the info pane and animate it into view
228 mInfoView.setVisibility(View.VISIBLE);
229 mInfoView.animateCircularClip(mLastTouchDown, 0f, 1f, null, true);
230 mInfoView.setOnClickListener(this);
231 mTaskInfoPaneVisible = true;
232
233 // Notify any callbacks
234 if (mCb != null) {
235 mCb.onTaskInfoPanelShown(this);
236 }
237 }
238
239 /** Hides the info pane if it is visible. */
240 void hideInfoPane() {
241 if (!mTaskInfoPaneVisible) return;
242 RecentsConfiguration config = RecentsConfiguration.getInstance();
243
244 // Cancel any circular clip animation
245 mInfoView.cancelCircularClipAnimation();
246
247 // Animate the info pane out
248 mInfoView.animate()
249 .alpha(0f)
250 .setDuration(config.taskViewInfoPaneAnimDuration)
251 .setInterpolator(BakedBezierInterpolator.INSTANCE)
252 .withLayer()
253 .withEndAction(new Runnable() {
254 @Override
255 public void run() {
256 mInfoView.setVisibility(View.INVISIBLE);
257 mInfoView.setOnClickListener(null);
258
259 mInfoView.setAlpha(1f);
260 }
261 })
262 .start();
263 mTaskInfoPaneVisible = false;
264
265 // Notify any callbacks
266 if (mCb != null) {
267 mCb.onTaskInfoPanelHidden(this);
268 }
269 }
270
Winson Chung303e1ff2014-03-07 15:06:19 -0800271 /** Enable the hw layers on this task view */
272 void enableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800273 mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
274 }
275
276 /** Disable the hw layers on this task view */
277 void disableHwLayers() {
Winson Chung303e1ff2014-03-07 15:06:19 -0800278 mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
279 }
280
Winson Chung4d7b0922014-03-13 17:14:17 -0700281 /**** TaskCallbacks Implementation ****/
282
Winson Chung04dfe0d2014-03-14 14:06:29 -0700283 /** Binds this task view to the task */
284 public void onTaskBound(Task t) {
285 mTask = t;
286 mTask.setCallbacks(this);
Winson Chung303e1ff2014-03-07 15:06:19 -0800287 }
288
289 @Override
Winson Chung4c71aef2014-03-21 15:15:11 -0700290 public void onTaskDataLoaded(boolean reloadingTaskData) {
Winson Chung9f9679d2014-04-11 16:49:09 -0700291 if (mThumbnailView != null && mBarView != null && mInfoView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700292 // Bind each of the views to the new task data
293 mThumbnailView.rebindToTask(mTask, reloadingTaskData);
294 mBarView.rebindToTask(mTask, reloadingTaskData);
Winson Chung9f9679d2014-04-11 16:49:09 -0700295 // Rebind any listeners
296 mBarView.mApplicationIcon.setOnClickListener(this);
297 mInfoView.mAppInfoButton.setOnClickListener(this);
Winson Chung37c8d8e2014-03-24 14:53:07 -0700298 }
299 mTaskDataLoaded = true;
Winson Chung4d7b0922014-03-13 17:14:17 -0700300 }
301
302 @Override
Winson Chung04dfe0d2014-03-14 14:06:29 -0700303 public void onTaskDataUnloaded() {
Winson Chung9f9679d2014-04-11 16:49:09 -0700304 if (mThumbnailView != null && mBarView != null && mInfoView != null) {
Winson Chung37c8d8e2014-03-24 14:53:07 -0700305 // Unbind each of the views from the task data and remove the task callback
306 mTask.setCallbacks(null);
307 mThumbnailView.unbindFromTask();
308 mBarView.unbindFromTask();
Winson Chung9f9679d2014-04-11 16:49:09 -0700309 // Unbind any listeners
310 mBarView.mApplicationIcon.setOnClickListener(null);
311 mInfoView.mAppInfoButton.setOnClickListener(null);
Winson Chung37c8d8e2014-03-24 14:53:07 -0700312 }
313 mTaskDataLoaded = false;
Winson Chung4d7b0922014-03-13 17:14:17 -0700314 }
315
316 @Override
Winson Chung303e1ff2014-03-07 15:06:19 -0800317 public void onClick(View v) {
Winson Chung9f9679d2014-04-11 16:49:09 -0700318 if (v == mInfoView) {
319 // Do nothing
320 } else if (v == mBarView.mApplicationIcon) {
321 mCb.onTaskIconClicked(this);
322 } else if (v == mInfoView.mAppInfoButton) {
323 mCb.onTaskAppInfoClicked(this);
324 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800325 }
326}