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.graphics.Bitmap; 24 import android.graphics.Canvas; 25 import android.util.AttributeSet; 26 import android.widget.ImageView; 27 28 import androidx.annotation.NonNull; 29 import androidx.annotation.Nullable; 30 import androidx.constraintlayout.widget.ConstraintLayout; 31 32 import com.android.launcher3.R; 33 import com.android.quickstep.util.BorderAnimator; 34 import com.android.systemui.shared.recents.model.Task; 35 import com.android.systemui.shared.recents.model.ThumbnailData; 36 37 import java.util.function.Consumer; 38 39 /** 40 * A view that displays a recent task during a keyboard quick switch. 41 */ 42 public class KeyboardQuickSwitchTaskView extends ConstraintLayout { 43 44 @NonNull private final BorderAnimator mBorderAnimator; 45 46 @Nullable private ImageView mThumbnailView1; 47 @Nullable private ImageView mThumbnailView2; 48 KeyboardQuickSwitchTaskView(@onNull Context context)49 public KeyboardQuickSwitchTaskView(@NonNull Context context) { 50 this(context, null); 51 } 52 KeyboardQuickSwitchTaskView(@onNull Context context, @Nullable AttributeSet attrs)53 public KeyboardQuickSwitchTaskView(@NonNull Context context, @Nullable AttributeSet attrs) { 54 this(context, attrs, 0); 55 } 56 KeyboardQuickSwitchTaskView( @onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)57 public KeyboardQuickSwitchTaskView( 58 @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 59 this(context, attrs, defStyleAttr, 0); 60 } 61 KeyboardQuickSwitchTaskView( @onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)62 public KeyboardQuickSwitchTaskView( 63 @NonNull Context context, 64 @Nullable AttributeSet attrs, 65 int defStyleAttr, 66 int defStyleRes) { 67 super(context, attrs, defStyleAttr, defStyleRes); 68 setWillNotDraw(false); 69 Resources resources = context.getResources(); 70 mBorderAnimator = new BorderAnimator( 71 /* borderBoundsBuilder= */ bounds -> bounds.set(0, 0, getWidth(), getHeight()), 72 /* borderWidthPx= */ resources.getDimensionPixelSize( 73 R.dimen.keyboard_quick_switch_border_width), 74 /* borderRadiusPx= */ resources.getDimensionPixelSize( 75 R.dimen.keyboard_quick_switch_task_view_radius), 76 /* borderColor= */ attrs == null 77 ? DEFAULT_BORDER_COLOR 78 : context.getTheme() 79 .obtainStyledAttributes( 80 attrs, 81 R.styleable.TaskView, 82 defStyleAttr, 83 defStyleRes) 84 .getColor( 85 R.styleable.TaskView_borderColor, 86 DEFAULT_BORDER_COLOR), 87 /* invalidateViewCallback= */ KeyboardQuickSwitchTaskView.this::invalidate); 88 } 89 90 @Override onFinishInflate()91 protected void onFinishInflate() { 92 super.onFinishInflate(); 93 94 mThumbnailView1 = findViewById(R.id.thumbnail1); 95 mThumbnailView2 = findViewById(R.id.thumbnail2); 96 } 97 98 @NonNull getFocusAnimator(boolean focused)99 protected Animator getFocusAnimator(boolean focused) { 100 return mBorderAnimator.buildAnimator(focused); 101 } 102 103 @Override draw(Canvas canvas)104 public void draw(Canvas canvas) { 105 super.draw(canvas); 106 mBorderAnimator.drawBorder(canvas); 107 } 108 setThumbnails( @onNull Task task1, @Nullable Task task2, @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction, @Nullable TitleUpdateFunction titleUpdateFunction)109 protected void setThumbnails( 110 @NonNull Task task1, 111 @Nullable Task task2, 112 @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction, 113 @Nullable TitleUpdateFunction titleUpdateFunction) { 114 applyThumbnail(mThumbnailView1, task1, thumbnailUpdateFunction); 115 applyThumbnail(mThumbnailView2, task2, thumbnailUpdateFunction); 116 117 if (titleUpdateFunction == null) { 118 setContentDescription(task2 == null 119 ? task1.titleDescription 120 : getContext().getString( 121 R.string.quick_switch_split_task, 122 task1.titleDescription, 123 task2.titleDescription)); 124 return; 125 } 126 titleUpdateFunction.updateTitleInBackground(task1, t -> 127 setContentDescription(task1.titleDescription)); 128 if (task2 == null) { 129 return; 130 } 131 titleUpdateFunction.updateTitleInBackground(task2, t -> 132 setContentDescription(getContext().getString( 133 R.string.quick_switch_split_task, 134 task1.titleDescription, 135 task2.titleDescription))); 136 } 137 applyThumbnail( @ullable ImageView thumbnailView, @Nullable Task task, @Nullable ThumbnailUpdateFunction updateFunction)138 private void applyThumbnail( 139 @Nullable ImageView thumbnailView, 140 @Nullable Task task, 141 @Nullable ThumbnailUpdateFunction updateFunction) { 142 if (thumbnailView == null) { 143 return; 144 } 145 if (task == null) { 146 return; 147 } 148 if (updateFunction == null) { 149 applyThumbnail(thumbnailView, task.thumbnail); 150 return; 151 } 152 updateFunction.updateThumbnailInBackground( 153 task, thumbnailData -> applyThumbnail(thumbnailView, thumbnailData)); 154 } 155 applyThumbnail( @onNull ImageView thumbnailView, ThumbnailData thumbnailData)156 private void applyThumbnail( 157 @NonNull ImageView thumbnailView, ThumbnailData thumbnailData) { 158 Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail; 159 160 thumbnailView.setVisibility(VISIBLE); 161 thumbnailView.setImageBitmap(bm); 162 } 163 164 protected interface ThumbnailUpdateFunction { 165 updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback)166 void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback); 167 } 168 169 protected interface TitleUpdateFunction { 170 updateTitleInBackground(Task task, Consumer<Task> callback)171 void updateTitleInBackground(Task task, Consumer<Task> callback); 172 } 173 } 174