1 /*
2  * Copyright (C) 2019 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 
17 package com.android.quickstep.views;
18 
19 import android.content.Context;
20 import android.graphics.drawable.Drawable;
21 import android.graphics.drawable.LayerDrawable;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.launcher3.R;
26 
27 /**
28  * A layer drawable for task content that transitions between two drawables by crossfading. Similar
29  * to {@link android.graphics.drawable.TransitionDrawable} but allows callers to control transition
30  * progress and provides a default, empty drawable.
31  */
32 public final class TaskLayerDrawable extends LayerDrawable {
33     private final Drawable mEmptyDrawable;
34     private float mProgress;
35 
TaskLayerDrawable(Context context)36     public TaskLayerDrawable(Context context) {
37         super(new Drawable[0]);
38 
39         // Use empty drawable for both layers initially.
40         mEmptyDrawable = context.getResources().getDrawable(
41                 R.drawable.empty_content_box, context.getTheme());
42         addLayer(mEmptyDrawable);
43         addLayer(mEmptyDrawable);
44         setTransitionProgress(1.0f);
45     }
46 
47     /**
48      * Immediately set the front-most drawable layer.
49      *
50      * @param drawable drawable to set
51      */
setCurrentDrawable(@onNull Drawable drawable)52     public void setCurrentDrawable(@NonNull Drawable drawable) {
53         setDrawable(0, drawable);
54         applyTransitionProgress(mProgress);
55     }
56 
57     /**
58      * Immediately reset the drawable to showing the empty drawable.
59      */
resetDrawable()60     public void resetDrawable() {
61         setCurrentDrawable(mEmptyDrawable);
62     }
63 
64     /**
65      * Prepare to start animating the transition by pushing the current drawable to the back and
66      * setting a new drawable to the front layer and making it invisible.
67      *
68      * @param endDrawable drawable to animate to
69      */
startNewTransition(@onNull Drawable endDrawable)70     public void startNewTransition(@NonNull Drawable endDrawable) {
71         Drawable oldDrawable = getDrawable(0);
72         setDrawable(1, oldDrawable);
73         setDrawable(0, endDrawable);
74         setTransitionProgress(0.0f);
75     }
76 
77     /**
78      * Set the progress of the transition animation to crossfade the two drawables.
79      *
80      * @param progress current transition progress between 0 (front view invisible) and 1
81      *                 (front view visible)
82      */
setTransitionProgress(float progress)83     public void setTransitionProgress(float progress) {
84         if (progress > 1 || progress < 0) {
85             throw new IllegalArgumentException("Transition progress should be between 0 and 1");
86         }
87         mProgress = progress;
88         applyTransitionProgress(progress);
89     }
90 
applyTransitionProgress(float progress)91     private void applyTransitionProgress(float progress) {
92         int drawableAlpha = (int) (progress * 255);
93         getDrawable(0).setAlpha(drawableAlpha);
94         if (getDrawable(0) != getDrawable(1)) {
95             // Only do this if it's a different drawable so that it fades out.
96             // Otherwise, we'd just be overwriting the front drawable's alpha.
97             getDrawable(1).setAlpha(255 - drawableAlpha);
98         }
99         invalidateSelf();
100     }
101 }
102