• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 package com.android.launcher3.taskbar;
17 
18 import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
19 
20 import android.animation.Animator;
21 import android.content.Context;
22 import android.content.res.Resources;
23 import android.content.res.TypedArray;
24 import android.graphics.Bitmap;
25 import android.graphics.Canvas;
26 import android.util.AttributeSet;
27 import android.view.View;
28 import android.widget.ImageView;
29 
30 import androidx.annotation.ColorInt;
31 import androidx.annotation.NonNull;
32 import androidx.annotation.Nullable;
33 import androidx.constraintlayout.widget.ConstraintLayout;
34 
35 import com.android.launcher3.R;
36 import com.android.launcher3.util.Preconditions;
37 import com.android.quickstep.util.BorderAnimator;
38 import com.android.systemui.shared.recents.model.Task;
39 import com.android.systemui.shared.recents.model.ThumbnailData;
40 
41 import java.util.function.Consumer;
42 
43 /**
44  * A view that displays a recent task during a keyboard quick switch.
45  */
46 public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
47 
48     @ColorInt private final int mBorderColor;
49 
50     @Nullable private BorderAnimator mBorderAnimator;
51 
52     @Nullable private ImageView mThumbnailView1;
53     @Nullable private ImageView mThumbnailView2;
54     @Nullable private ImageView mIcon1;
55     @Nullable private ImageView mIcon2;
56     @Nullable private View mContent;
57 
KeyboardQuickSwitchTaskView(@onNull Context context)58     public KeyboardQuickSwitchTaskView(@NonNull Context context) {
59         this(context, null);
60     }
61 
KeyboardQuickSwitchTaskView(@onNull Context context, @Nullable AttributeSet attrs)62     public KeyboardQuickSwitchTaskView(@NonNull Context context, @Nullable AttributeSet attrs) {
63         this(context, attrs, 0);
64     }
65 
KeyboardQuickSwitchTaskView( @onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)66     public KeyboardQuickSwitchTaskView(
67             @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
68         this(context, attrs, defStyleAttr, 0);
69     }
70 
KeyboardQuickSwitchTaskView( @onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)71     public KeyboardQuickSwitchTaskView(
72             @NonNull Context context,
73             @Nullable AttributeSet attrs,
74             int defStyleAttr,
75             int defStyleRes) {
76         super(context, attrs, defStyleAttr, defStyleRes);
77         TypedArray ta = context.obtainStyledAttributes(
78                 attrs, R.styleable.TaskView, defStyleAttr, defStyleRes);
79 
80         setWillNotDraw(false);
81 
82         mBorderColor = ta.getColor(
83                 R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR);
84         ta.recycle();
85     }
86 
87     @Override
onFinishInflate()88     protected void onFinishInflate() {
89         super.onFinishInflate();
90         mThumbnailView1 = findViewById(R.id.thumbnail1);
91         mThumbnailView2 = findViewById(R.id.thumbnail2);
92         mIcon1 = findViewById(R.id.icon1);
93         mIcon2 = findViewById(R.id.icon2);
94         mContent = findViewById(R.id.content);
95 
96         Resources resources = mContext.getResources();
97 
98         Preconditions.assertNotNull(mContent);
99         mBorderAnimator = new BorderAnimator(
100                 /* borderRadiusPx= */ resources.getDimensionPixelSize(
101                         R.dimen.keyboard_quick_switch_task_view_radius),
102                 /* borderColor= */ mBorderColor,
103                 /* borderAnimationParams= */ new BorderAnimator.ScalingParams(
104                         /* borderWidthPx= */ resources.getDimensionPixelSize(
105                                 R.dimen.keyboard_quick_switch_border_width),
106                         /* boundsBuilder= */ bounds -> bounds.set(
107                                 0, 0, getWidth(), getHeight()),
108                         /* targetView= */ this,
109                         /* contentView= */ mContent));
110     }
111 
112     @Nullable
getFocusAnimator(boolean focused)113     protected Animator getFocusAnimator(boolean focused) {
114         return mBorderAnimator == null ? null : mBorderAnimator.buildAnimator(focused);
115     }
116 
117     @Override
draw(Canvas canvas)118     public void draw(Canvas canvas) {
119         super.draw(canvas);
120         if (mBorderAnimator != null) {
121             mBorderAnimator.drawBorder(canvas);
122         }
123     }
124 
setThumbnails( @onNull Task task1, @Nullable Task task2, @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction, @Nullable IconUpdateFunction iconUpdateFunction)125     protected void setThumbnails(
126             @NonNull Task task1,
127             @Nullable Task task2,
128             @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction,
129             @Nullable IconUpdateFunction iconUpdateFunction) {
130         applyThumbnail(mThumbnailView1, task1, thumbnailUpdateFunction);
131         applyThumbnail(mThumbnailView2, task2, thumbnailUpdateFunction);
132 
133         if (iconUpdateFunction == null) {
134             applyIcon(mIcon1, task1);
135             applyIcon(mIcon2, task2);
136             setContentDescription(task2 == null
137                     ? task1.titleDescription
138                     : getContext().getString(
139                             R.string.quick_switch_split_task,
140                             task1.titleDescription,
141                             task2.titleDescription));
142             return;
143         }
144         iconUpdateFunction.updateIconInBackground(task1, t -> {
145             applyIcon(mIcon1, task1);
146             if (task2 != null) {
147                 return;
148             }
149             setContentDescription(task1.titleDescription);
150         });
151         if (task2 == null) {
152             return;
153         }
154         iconUpdateFunction.updateIconInBackground(task2, t -> {
155             applyIcon(mIcon2, task2);
156             setContentDescription(getContext().getString(
157                     R.string.quick_switch_split_task,
158                     task1.titleDescription,
159                     task2.titleDescription));
160         });
161     }
162 
applyThumbnail( @ullable ImageView thumbnailView, @Nullable Task task, @Nullable ThumbnailUpdateFunction updateFunction)163     private void applyThumbnail(
164             @Nullable ImageView thumbnailView,
165             @Nullable Task task,
166             @Nullable ThumbnailUpdateFunction updateFunction) {
167         if (thumbnailView == null) {
168             return;
169         }
170         if (task == null) {
171             return;
172         }
173         if (updateFunction == null) {
174             applyThumbnail(thumbnailView, task.thumbnail);
175             return;
176         }
177         updateFunction.updateThumbnailInBackground(
178                 task, thumbnailData -> applyThumbnail(thumbnailView, thumbnailData));
179     }
180 
applyThumbnail( @onNull ImageView thumbnailView, ThumbnailData thumbnailData)181     private void applyThumbnail(
182             @NonNull ImageView thumbnailView, ThumbnailData thumbnailData) {
183         Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail;
184 
185         thumbnailView.setVisibility(VISIBLE);
186         thumbnailView.setImageBitmap(bm);
187     }
188 
applyIcon(@ullable ImageView iconView, @Nullable Task task)189     private void applyIcon(@Nullable ImageView iconView, @Nullable Task task) {
190         if (iconView == null || task == null) {
191             return;
192         }
193         iconView.setVisibility(VISIBLE);
194         iconView.setImageDrawable(task.icon);
195     }
196 
197     protected interface ThumbnailUpdateFunction {
198 
updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback)199         void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback);
200     }
201 
202     protected interface IconUpdateFunction {
203 
updateIconInBackground(Task task, Consumer<Task> callback)204         void updateIconInBackground(Task task, Consumer<Task> callback);
205     }
206 }
207