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 package com.android.quickstep.views; 17 18 import android.content.Context; 19 import android.content.res.Configuration; 20 import android.content.res.Resources; 21 import android.graphics.drawable.Drawable; 22 import android.util.AttributeSet; 23 import android.util.FloatProperty; 24 import android.view.View; 25 import android.widget.ImageView; 26 import android.widget.LinearLayout; 27 import android.widget.TextView; 28 29 import androidx.annotation.NonNull; 30 import androidx.annotation.Nullable; 31 32 import com.android.launcher3.R; 33 import com.android.quickstep.ThumbnailDrawable; 34 import com.android.systemui.shared.recents.model.ThumbnailData; 35 36 /** 37 * View representing an individual task item with the icon + thumbnail adjacent to the task label. 38 */ 39 public final class TaskItemView extends LinearLayout { 40 41 private static final String EMPTY_LABEL = ""; 42 private static final String DEFAULT_LABEL = "..."; 43 private final Drawable mDefaultIcon; 44 private final Drawable mDefaultThumbnail; 45 private final TaskLayerDrawable mIconDrawable; 46 private final TaskLayerDrawable mThumbnailDrawable; 47 private View mTaskIconThumbnailView; 48 private TextView mLabelView; 49 private ImageView mIconView; 50 private ImageView mThumbnailView; 51 private float mContentTransitionProgress; 52 private int mDisplayedOrientation; 53 54 /** 55 * Property representing the content transition progress of the view. 1.0f represents that the 56 * currently bound icon, thumbnail, and label are fully animated in and visible. 57 */ 58 public static FloatProperty CONTENT_TRANSITION_PROGRESS = 59 new FloatProperty<TaskItemView>("taskContentTransitionProgress") { 60 @Override 61 public void setValue(TaskItemView view, float progress) { 62 view.setContentTransitionProgress(progress); 63 } 64 65 @Override 66 public Float get(TaskItemView view) { 67 return view.mContentTransitionProgress; 68 } 69 }; 70 TaskItemView(Context context, AttributeSet attrs)71 public TaskItemView(Context context, AttributeSet attrs) { 72 super(context, attrs); 73 Resources res = context.getResources(); 74 mDefaultIcon = res.getDrawable(android.R.drawable.sym_def_app_icon, context.getTheme()); 75 mDefaultThumbnail = res.getDrawable(R.drawable.default_thumbnail, context.getTheme()); 76 mIconDrawable = new TaskLayerDrawable(context); 77 mThumbnailDrawable = new TaskLayerDrawable(context); 78 } 79 80 @Override onFinishInflate()81 protected void onFinishInflate() { 82 super.onFinishInflate(); 83 mLabelView = findViewById(R.id.task_label); 84 mTaskIconThumbnailView = findViewById(R.id.task_icon_and_thumbnail); 85 mThumbnailView = findViewById(R.id.task_thumbnail); 86 mIconView = findViewById(R.id.task_icon); 87 88 mThumbnailView.setImageDrawable(mThumbnailDrawable); 89 mIconView.setImageDrawable(mIconDrawable); 90 91 resetToEmptyUi(); 92 CONTENT_TRANSITION_PROGRESS.setValue(this, 1.0f); 93 } 94 95 /** 96 * Resets task item view to empty, loading UI. 97 */ resetToEmptyUi()98 public void resetToEmptyUi() { 99 mIconDrawable.resetDrawable(); 100 mThumbnailDrawable.resetDrawable(); 101 setLabel(EMPTY_LABEL); 102 } 103 104 /** 105 * Set the label for the task item. Sets to a default label if null. 106 * 107 * @param label task label 108 */ setLabel(@ullable String label)109 public void setLabel(@Nullable String label) { 110 mLabelView.setText(getSafeLabel(label)); 111 // TODO: Animation for label 112 } 113 114 /** 115 * Set the icon for the task item. Sets to a default icon if null. 116 * 117 * @param icon task icon 118 */ setIcon(@ullable Drawable icon)119 public void setIcon(@Nullable Drawable icon) { 120 // TODO: Scale the icon up based off the padding on the side 121 // The icon proper is actually smaller than the drawable and has "padding" on the side for 122 // the purpose of drawing the shadow, allowing the icon to pop up, so we need to scale the 123 // view if we want the icon to be flush with the bottom of the thumbnail. 124 mIconDrawable.setCurrentDrawable(getSafeIcon(icon)); 125 } 126 127 /** 128 * Set the task thumbnail for the task. Sets to a default thumbnail if null. 129 * 130 * @param thumbnailData task thumbnail data for the task 131 */ setThumbnail(@ullable ThumbnailData thumbnailData)132 public void setThumbnail(@Nullable ThumbnailData thumbnailData) { 133 mThumbnailDrawable.setCurrentDrawable(getSafeThumbnail(thumbnailData)); 134 } 135 getThumbnailView()136 public View getThumbnailView() { 137 return mThumbnailView; 138 } 139 getIconView()140 public View getIconView() { 141 return mIconView; 142 } 143 getLabelView()144 public View getLabelView() { 145 return mLabelView; 146 } 147 148 /** 149 * Start a new animation from the current task content to the specified new content. The caller 150 * is responsible for the actual animation control via the property 151 * {@link #CONTENT_TRANSITION_PROGRESS}. 152 * 153 * @param endIcon the icon to animate to 154 * @param endThumbnail the thumbnail to animate to 155 * @param endLabel the label to animate to 156 */ startContentAnimation(@ullable Drawable endIcon, @Nullable ThumbnailData endThumbnail, @Nullable String endLabel)157 public void startContentAnimation(@Nullable Drawable endIcon, 158 @Nullable ThumbnailData endThumbnail, @Nullable String endLabel) { 159 mIconDrawable.startNewTransition(getSafeIcon(endIcon)); 160 mThumbnailDrawable.startNewTransition(getSafeThumbnail(endThumbnail)); 161 // TODO: Animation for label 162 163 setContentTransitionProgress(0.0f); 164 } 165 setContentTransitionProgress(float progress)166 private void setContentTransitionProgress(float progress) { 167 mContentTransitionProgress = progress; 168 mIconDrawable.setTransitionProgress(progress); 169 mThumbnailDrawable.setTransitionProgress(progress); 170 // TODO: Animation for label 171 } 172 getSafeIcon(@ullable Drawable icon)173 private @NonNull Drawable getSafeIcon(@Nullable Drawable icon) { 174 return (icon != null) ? icon : mDefaultIcon; 175 } 176 getSafeThumbnail(@ullable ThumbnailData thumbnailData)177 private @NonNull Drawable getSafeThumbnail(@Nullable ThumbnailData thumbnailData) { 178 if (thumbnailData == null || thumbnailData.thumbnail == null) { 179 return mDefaultThumbnail; 180 } 181 int orientation = getResources().getConfiguration().orientation; 182 return new ThumbnailDrawable(getResources(), thumbnailData, 183 orientation /* requestedOrientation */); 184 } 185 getSafeLabel(@ullable String label)186 private @NonNull String getSafeLabel(@Nullable String label) { 187 return (label != null) ? label : DEFAULT_LABEL; 188 } 189 190 @Override onAttachedToWindow()191 protected void onAttachedToWindow() { 192 super.onAttachedToWindow(); 193 onOrientationChanged(getResources().getConfiguration().orientation); 194 } 195 196 @Override onConfigurationChanged(Configuration newConfig)197 protected void onConfigurationChanged(Configuration newConfig) { 198 super.onConfigurationChanged(newConfig); 199 onOrientationChanged(newConfig.orientation); 200 } 201 onOrientationChanged(int newOrientation)202 private void onOrientationChanged(int newOrientation) { 203 if (mDisplayedOrientation == newOrientation) { 204 return; 205 } 206 mDisplayedOrientation = newOrientation; 207 int layerCount = mThumbnailDrawable.getNumberOfLayers(); 208 for (int i = 0; i < layerCount; i++) { 209 Drawable drawable = mThumbnailDrawable.getDrawable(i); 210 if (drawable instanceof ThumbnailDrawable) { 211 ((ThumbnailDrawable) drawable).setRequestedOrientation(newOrientation); 212 } 213 } 214 mTaskIconThumbnailView.forceLayout(); 215 } 216 } 217