TaskView.java revision 2f2ca08baa072376b3dfd60506625496aa05903f
1/*
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
19import android.animation.Animator;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
22import android.content.Context;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25import android.graphics.Color;
26import android.graphics.Path;
27import android.graphics.Rect;
28import android.graphics.RectF;
29import android.util.AttributeSet;
30import android.view.View;
31import android.widget.FrameLayout;
32import com.android.systemui.R;
33import com.android.systemui.recents.BakedBezierInterpolator;
34import com.android.systemui.recents.Constants;
35import com.android.systemui.recents.RecentsConfiguration;
36import com.android.systemui.recents.Utilities;
37import com.android.systemui.recents.model.Task;
38
39import java.util.Random;
40
41
42/* A task view */
43public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks {
44    /** The TaskView callbacks */
45    interface TaskViewCallbacks {
46        public void onTaskIconClicked(TaskView tv);
47        // public void onTaskViewReboundToTask(TaskView tv, Task t);
48    }
49
50    Task mTask;
51    boolean mTaskDataLoaded;
52
53    TaskThumbnailView mThumbnailView;
54    TaskBarView mBarView;
55    TaskViewCallbacks mCb;
56
57    Path mRoundedRectClipPath = new Path();
58
59
60    public TaskView(Context context) {
61        this(context, null);
62    }
63
64    public TaskView(Context context, AttributeSet attrs) {
65        this(context, attrs, 0);
66    }
67
68    public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
69        this(context, attrs, defStyleAttr, 0);
70    }
71
72    public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
73        super(context, attrs, defStyleAttr, defStyleRes);
74        setWillNotDraw(false);
75    }
76
77    @Override
78    protected void onFinishInflate() {
79        // Bind the views
80        mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
81        mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
82        mBarView.mApplicationIcon.setOnClickListener(this);
83        if (mTaskDataLoaded) {
84            onTaskDataLoaded(false);
85        }
86    }
87
88    @Override
89    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
90        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
91
92        // Update the rounded rect clip path
93        RecentsConfiguration config = RecentsConfiguration.getInstance();
94        float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps);
95        mRoundedRectClipPath.reset();
96        mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
97                radius, radius, Path.Direction.CW);
98    }
99
100    @Override
101    protected void dispatchDraw(Canvas canvas) {
102        int restoreCount = 0;
103        if (Constants.Values.TaskView.UseRoundedCorners) {
104            restoreCount = canvas.save();
105            canvas.clipPath(mRoundedRectClipPath);
106        }
107        super.dispatchDraw(canvas);
108        if (Constants.Values.TaskView.UseRoundedCorners) {
109            canvas.restoreToCount(restoreCount);
110        }
111    }
112
113    /** Set callback */
114    void setCallbacks(TaskViewCallbacks cb) {
115        mCb = cb;
116    }
117
118    /** Gets the task */
119    Task getTask() {
120        return mTask;
121    }
122
123    /** Synchronizes this view's properties with the task's transform */
124    void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
125                                             TaskViewTransform toTransform, int duration) {
126        if (duration > 0) {
127            if (animateFromTransform != null) {
128                setTranslationY(animateFromTransform.translationY);
129                setScaleX(animateFromTransform.scale);
130                setScaleY(animateFromTransform.scale);
131                setAlpha(animateFromTransform.alpha);
132            }
133            animate().translationY(toTransform.translationY)
134                    .scaleX(toTransform.scale)
135                    .scaleY(toTransform.scale)
136                    .alpha(toTransform.alpha)
137                    .setDuration(duration)
138                    .setInterpolator(BakedBezierInterpolator.INSTANCE)
139                    .withLayer()
140                    .start();
141        } else {
142            setTranslationY(toTransform.translationY);
143            setScaleX(toTransform.scale);
144            setScaleY(toTransform.scale);
145            setAlpha(toTransform.alpha);
146        }
147    }
148
149    /** Returns an animator to animate this task to the specified transform */
150    Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
151        AnimatorSet anims = new AnimatorSet();
152        anims.playTogether(
153                ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
154                ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
155                ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
156                ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
157        );
158        return anims;
159    }
160
161    /** Resets this view's properties */
162    void resetViewProperties() {
163        setTranslationX(0f);
164        setTranslationY(0f);
165        setScaleX(1f);
166        setScaleY(1f);
167        setAlpha(1f);
168    }
169
170    void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
171        // Fade the view out and slide it away
172        toTransform.alpha = 0f;
173        toTransform.translationY += 200;
174    }
175
176    void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
177        // Fade the view in
178        fromTransform.alpha = 0f;
179    }
180
181    /** Animates this task view as it enters recents */
182    public void animateOnEnterRecents() {
183        RecentsConfiguration config = RecentsConfiguration.getInstance();
184        int translate = config.pxFromDp(10);
185        mBarView.setScaleX(1.25f);
186        mBarView.setScaleY(1.25f);
187        mBarView.setAlpha(0f);
188        mBarView.setTranslationX(translate / 2);
189        mBarView.setTranslationY(-translate);
190        mBarView.animate()
191                .alpha(1f)
192                .scaleX(1f)
193                .scaleY(1f)
194                .translationX(0)
195                .translationY(0)
196                .setStartDelay(235)
197                .setInterpolator(BakedBezierInterpolator.INSTANCE)
198                .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
199                .withLayer()
200                .start();
201    }
202
203    /** Animates this task view as it exits recents */
204    public void animateOnLeavingRecents(final Runnable r) {
205        RecentsConfiguration config = RecentsConfiguration.getInstance();
206        int translate = config.pxFromDp(10);
207        mBarView.animate()
208            .alpha(0f)
209            .scaleX(1.1f)
210            .scaleY(1.1f)
211            .translationX(translate / 2)
212            .translationY(-translate)
213            .setStartDelay(0)
214            .setInterpolator(BakedBezierInterpolator.INSTANCE)
215            .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
216            .withLayer()
217            .withEndAction(r)
218            .start();
219    }
220
221    /** Returns the rect we want to clip (it may not be the full rect) */
222    Rect getClippingRect(Rect outRect, boolean accountForRoundedRects) {
223        getHitRect(outRect);
224        // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
225        outRect.right = outRect.left + mThumbnailView.getRight();
226        outRect.bottom = outRect.top + mThumbnailView.getBottom();
227        // We need to shrink the next rect by the rounded corners since those are draw on
228        // top of the current view
229        if (accountForRoundedRects) {
230            RecentsConfiguration config = RecentsConfiguration.getInstance();
231            float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps);
232            outRect.inset((int) radius, (int) radius);
233        }
234        return outRect;
235    }
236
237    /** Enable the hw layers on this task view */
238    void enableHwLayers() {
239        mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
240    }
241
242    /** Disable the hw layers on this task view */
243    void disableHwLayers() {
244        mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
245    }
246
247    /**** TaskCallbacks Implementation ****/
248
249    /** Binds this task view to the task */
250    public void onTaskBound(Task t) {
251        mTask = t;
252        mTask.setCallbacks(this);
253    }
254
255    @Override
256    public void onTaskDataLoaded(boolean reloadingTaskData) {
257        if (mThumbnailView != null && mBarView != null) {
258            // Bind each of the views to the new task data
259            mThumbnailView.rebindToTask(mTask, reloadingTaskData);
260            mBarView.rebindToTask(mTask, reloadingTaskData);
261        }
262        mTaskDataLoaded = true;
263    }
264
265    @Override
266    public void onTaskDataUnloaded() {
267        if (mThumbnailView != null && mBarView != null) {
268            // Unbind each of the views from the task data and remove the task callback
269            mTask.setCallbacks(null);
270            mThumbnailView.unbindFromTask();
271            mBarView.unbindFromTask();
272        }
273        mTaskDataLoaded = false;
274    }
275
276    @Override
277    public void onClick(View v) {
278        mCb.onTaskIconClicked(this);
279    }
280}