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