Add a refactored TaskThumbnailView

- Live Tile, swipe (left+right) and dismiss working
- Tests of ViewModel state transitions
- Deprecate the old TaskThumbnailView
- Renaming TaskThumbnailView to TaskThumbnailViewDeprecated

Fix: 335440878
Fix: 331754672
Bug: 331753115
Test: TaskThumbnailViewModelTest
Test: Attached video on bug
Flag: ACONFIG com.android.launcher3.enable_refactor_task_thumbnail DEVELOPMENT
Change-Id: I063b957fe6e56960970dcaadc641848fbd73251c
This commit is contained in:
Uwais Ashraf
2024-04-17 16:32:32 +00:00
committed by Jordan Silva
parent 782af232e3
commit e21525da40
21 changed files with 517 additions and 153 deletions
@@ -46,7 +46,7 @@ import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
@@ -107,7 +107,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
return shortcuts;
}
public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
public TaskOverlay createOverlay(TaskThumbnailViewDeprecated thumbnailView) {
return new TaskOverlay(thumbnailView);
}
@@ -149,14 +149,14 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
public static class TaskOverlay<T extends OverviewActionsView> {
protected final Context mApplicationContext;
protected final TaskThumbnailView mThumbnailView;
protected final TaskThumbnailViewDeprecated mThumbnailView;
private T mActionsView;
protected ImageActionsApi mImageApi;
protected TaskOverlay(TaskThumbnailView taskThumbnailView) {
mApplicationContext = taskThumbnailView.getContext().getApplicationContext();
mThumbnailView = taskThumbnailView;
protected TaskOverlay(TaskThumbnailViewDeprecated taskThumbnailViewDeprecated) {
mApplicationContext = taskThumbnailViewDeprecated.getContext().getApplicationContext();
mThumbnailView = taskThumbnailViewDeprecated;
mImageApi = new ImageActionsApi(
mApplicationContext, mThumbnailView::getThumbnail);
}
@@ -169,7 +169,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
return mActionsView;
}
public TaskThumbnailView getThumbnailView() {
public TaskThumbnailViewDeprecated getThumbnailView() {
return mThumbnailView;
}
@@ -53,7 +53,7 @@ import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
@@ -158,7 +158,7 @@ public interface TaskShortcutFactory {
private Handler mHandler;
private final RecentsView mRecentsView;
private final TaskThumbnailView mThumbnailView;
private final TaskThumbnailViewDeprecated mThumbnailView;
private final TaskView mTaskView;
private final LauncherEvent mLauncherEvent;
@@ -80,7 +80,7 @@ import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
import com.android.systemui.animation.RemoteAnimationTargetCompat;
import com.android.systemui.shared.recents.model.Task;
@@ -334,7 +334,7 @@ public final class TaskViewUtils {
// During animation we apply transformation on the thumbnailView (and not the rootView)
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
// Mt K(0)` K(t) Mt`
TaskThumbnailView[] thumbnails = v.getThumbnails();
TaskThumbnailViewDeprecated[] thumbnails = v.getThumbnails();
// In case simulator copies and thumbnail size do no match, ensure we get the lesser.
// This ensures we do not create arrays with empty elements or attempt to references
@@ -344,7 +344,7 @@ public final class TaskViewUtils {
Matrix[] mt = new Matrix[matrixSize];
Matrix[] mti = new Matrix[matrixSize];
for (int i = 0; i < matrixSize; i++) {
TaskThumbnailView ttv = thumbnails[i];
TaskThumbnailViewDeprecated ttv = thumbnails[i];
RectF localBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
@@ -391,7 +391,7 @@ public final class TaskViewUtils {
out.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
for (TaskThumbnailView ttv : thumbnails) {
for (TaskThumbnailViewDeprecated ttv : thumbnails) {
ttv.setAnimationMatrix(null);
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.task.thumbnail
import com.android.systemui.shared.recents.model.Task
sealed class TaskThumbnailUiState {
data object Uninitialized : TaskThumbnailUiState()
data object LiveTile : TaskThumbnailUiState()
}
data class TaskThumbnail(val task: Task, val isRunning: Boolean)
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.task.thumbnail
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.util.AttributeSet
import android.view.View
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.*
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
class TaskThumbnailView : View {
// TODO(b/335649589): Ideally create and obtain this from DI. This ViewModel should be scoped
// to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
val viewModel = TaskThumbnailViewModel()
private var uiState: TaskThumbnailUiState = Uninitialized
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
) : super(context, attrs, defStyleAttr)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// TODO(b/335396935) replace MainScope with shorter lifecycle.
MainScope().launch {
viewModel.uiState.collect { viewModelUiState ->
uiState = viewModelUiState
invalidate()
}
}
}
override fun onDraw(canvas: Canvas) {
when (uiState) {
is Uninitialized -> {}
is LiveTile -> drawTransparentUiState(canvas)
}
}
private fun drawTransparentUiState(canvas: Canvas) {
canvas.drawRoundRect(
0f,
0f,
measuredWidth.toFloat(),
measuredHeight.toFloat(),
// TODO(b/334826840) add rounded corners
0f,
0f,
CLEAR_PAINT
)
}
companion object {
private val CLEAR_PAINT =
Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.task.thumbnail
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class TaskThumbnailViewModel {
private val _uiState: MutableStateFlow<TaskThumbnailUiState> =
MutableStateFlow(TaskThumbnailUiState.Uninitialized)
val uiState: StateFlow<TaskThumbnailUiState> = _uiState
fun bind(task: TaskThumbnail) {
_uiState.value =
if (task.isRunning) {
TaskThumbnailUiState.LiveTile
} else {
TaskThumbnailUiState.Uninitialized
}
}
}
@@ -65,7 +65,7 @@ import com.android.quickstep.views.IconAppChipView
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.SplitInstructionsView
import com.android.quickstep.views.TaskThumbnailView
import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
import com.android.quickstep.views.TaskViewIcon
@@ -160,9 +160,9 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
/**
* When selecting first app from split pair, second app's thumbnail remains. This animates the
* second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it
* with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. Note: The app
* that **was not** selected as the first split app should be the container that's passed
* through.
* with [TaskThumbnailViewDeprecated]'s splashView. Adds animations to the provided builder.
* Note: The app that **was not** selected as the first split app should be the container that's
* passed through.
*
* @param builder Adds animation to this
* @param taskIdAttributeContainer container of the app that **was not** selected
@@ -179,7 +179,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
) {
val thumbnail = taskIdAttributeContainer.thumbnailView
val iconView: View = taskIdAttributeContainer.iconView.asView()
builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailViewDeprecated.SPLASH_ALPHA, 1f))
thumbnail.setShowSplashForSplitSelection(true)
// With the new `IconAppChipView`, we always want to keep the chip pinned to the
// top left of the task / thumbnail.
@@ -202,7 +202,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X,
TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
centerThumbnailTranslationX
)
)
@@ -224,7 +224,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
translateYResetVal
)
)
@@ -252,7 +252,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
centerThumbnailTranslationY
)
)
@@ -266,7 +266,11 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
// Reset other dimensions
thumbnail.scaleX = 1f
builder.add(
ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f)
ObjectAnimator.ofFloat(
thumbnail,
TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
0f
)
)
}
}
@@ -276,43 +280,59 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
* [pendingAnimation]. Assumes that animation will be the final split placeholder launch anim.
*
* [secondPlaceholderEndingBounds] refers to the second placeholder view that gets added on
* screen, not the logical second app.
* For landscape it's the left app and for portrait the top one.
* screen, not the logical second app. For landscape it's the left app and for portrait the top
* one.
*/
fun addDividerPlaceholderViewToAnim(pendingAnimation: PendingAnimation,
container: RecentsViewContainer,
secondPlaceholderEndingBounds: Rect,
context: Context) : View {
fun addDividerPlaceholderViewToAnim(
pendingAnimation: PendingAnimation,
container: RecentsViewContainer,
secondPlaceholderEndingBounds: Rect,
context: Context
): View {
val mSplitDividerPlaceholderView = View(context)
val recentsView = container.getOverviewPanel<RecentsView<*, *>>()
val dp : com.android.launcher3.DeviceProfile = container.getDeviceProfile()
val dp: com.android.launcher3.DeviceProfile = container.getDeviceProfile()
// Add it before/under the most recently added first floating taskView
val firstAddedSplitViewIndex: Int = container.getDragLayer().indexOfChild(
recentsView.splitSelectController.firstFloatingTaskView)
val firstAddedSplitViewIndex: Int =
container
.getDragLayer()
.indexOfChild(recentsView.splitSelectController.firstFloatingTaskView)
container.getDragLayer().addView(mSplitDividerPlaceholderView, firstAddedSplitViewIndex)
val lp = mSplitDividerPlaceholderView.layoutParams as InsettableFrameLayout.LayoutParams
lp.topMargin = 0
if (dp.isLeftRightSplit) {
lp.height = secondPlaceholderEndingBounds.height()
lp.width = container.asContext().resources.
getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
mSplitDividerPlaceholderView.translationX = secondPlaceholderEndingBounds.right - lp.width / 2f
lp.width =
container
.asContext()
.resources
.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
mSplitDividerPlaceholderView.translationX =
secondPlaceholderEndingBounds.right - lp.width / 2f
mSplitDividerPlaceholderView.translationY = 0f
} else {
lp.height = container.asContext().resources
lp.height =
container
.asContext()
.resources
.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
lp.width = secondPlaceholderEndingBounds.width()
mSplitDividerPlaceholderView.translationY = secondPlaceholderEndingBounds.top - lp.height / 2f
mSplitDividerPlaceholderView.translationY =
secondPlaceholderEndingBounds.top - lp.height / 2f
mSplitDividerPlaceholderView.translationX = 0f
}
mSplitDividerPlaceholderView.alpha = 0f
mSplitDividerPlaceholderView.setBackgroundColor(container.asContext().resources
.getColor(R.color.taskbar_background_dark))
mSplitDividerPlaceholderView.setBackgroundColor(
container.asContext().resources.getColor(R.color.taskbar_background_dark)
)
val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet)
pendingAnimation.setViewAlpha(mSplitDividerPlaceholderView, 1f,
Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f))
pendingAnimation.setViewAlpha(
mSplitDividerPlaceholderView,
1f,
Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f)
)
return mSplitDividerPlaceholderView
}
@@ -74,10 +74,10 @@ public class DesktopTaskView extends TaskView {
@NonNull
private List<Task> mTasks = new ArrayList<>();
private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>();
private final ArrayList<TaskThumbnailViewDeprecated> mSnapshotViews = new ArrayList<>();
/** Maps {@code taskIds} to corresponding {@link TaskThumbnailView}s */
private final SparseArray<TaskThumbnailView> mSnapshotViewMap = new SparseArray<>();
/** Maps {@code taskIds} to corresponding {@link TaskThumbnailViewDeprecated}s */
private final SparseArray<TaskThumbnailViewDeprecated> mSnapshotViewMap = new SparseArray<>();
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
@@ -175,13 +175,14 @@ public class DesktopTaskView extends TaskView {
if (mSnapshotViews.size() > mTasks.size()) {
int diff = mSnapshotViews.size() - mTasks.size();
for (int i = 0; i < diff; i++) {
TaskThumbnailView snapshotView = mSnapshotViews.remove(0);
TaskThumbnailViewDeprecated snapshotView = mSnapshotViews.remove(0);
removeView(snapshotView);
}
} else if (mSnapshotViews.size() < mTasks.size()) {
int diff = mTasks.size() - mSnapshotViews.size();
for (int i = 0; i < diff; i++) {
TaskThumbnailView snapshotView = new TaskThumbnailView(getContext());
TaskThumbnailViewDeprecated snapshotView =
new TaskThumbnailViewDeprecated(getContext());
mSnapshotViews.add(snapshotView);
// Add snapshots from to position after the initial child views.
addView(snapshotView, mChildCountAtInflation,
@@ -191,7 +192,7 @@ public class DesktopTaskView extends TaskView {
for (int i = 0; i < mTasks.size(); i++) {
Task task = mTasks.get(i);
TaskThumbnailView snapshotView = mSnapshotViews.get(i);
TaskThumbnailViewDeprecated snapshotView = mSnapshotViews.get(i);
snapshotView.bind(task);
mSnapshotViewMap.put(task.key.id, snapshotView);
}
@@ -217,13 +218,13 @@ public class DesktopTaskView extends TaskView {
mTaskIdAttributeContainer = new TaskIdAttributeContainer[Math.max(mTasks.size(), 2)];
for (int i = 0; i < mTasks.size(); i++) {
Task task = mTasks.get(i);
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView);
}
}
private TaskIdAttributeContainer createAttributeContainer(Task task,
TaskThumbnailView thumbnailView) {
TaskThumbnailViewDeprecated thumbnailView) {
return new TaskIdAttributeContainer(task, thumbnailView, createIconView(task),
STAGE_POSITION_UNDEFINED);
}
@@ -250,14 +251,14 @@ public class DesktopTaskView extends TaskView {
}
@Override
public TaskThumbnailView getThumbnail() {
public TaskThumbnailViewDeprecated getThumbnail() {
// TODO(b/249371338): returning single thumbnail. This won't work well with multiple tasks.
Task task = getTask();
if (task != null) {
return mSnapshotViewMap.get(task.key.id);
}
// Return the place holder snapshot views. Callers expect this to be non-null
return mSnapshotView;
return mTaskThumbnailViewDeprecated;
}
@Override
@@ -277,7 +278,8 @@ public class DesktopTaskView extends TaskView {
for (Task task : mTasks) {
CancellableTask<?> thumbLoadRequest =
thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> {
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
TaskThumbnailViewDeprecated thumbnailView =
mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.setThumbnail(task, thumbnailData);
}
@@ -290,7 +292,7 @@ public class DesktopTaskView extends TaskView {
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
for (Task task : mTasks) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.setThumbnail(null, null);
}
@@ -306,11 +308,11 @@ public class DesktopTaskView extends TaskView {
DeviceProfile deviceProfile = mContainer.getDeviceProfile();
int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
LayoutParams snapshotParams = (LayoutParams) mTaskThumbnailViewDeprecated.getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.valueAt(i);
thumbnailView.setLayoutParams(snapshotParams);
}
}
@@ -367,11 +369,11 @@ public class DesktopTaskView extends TaskView {
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
// Sets new thumbnails based on the incoming data and refreshes the rest.
// Create a copy of the thumbnail map, so we can track thumbnails that need refreshing.
SparseArray<TaskThumbnailView> thumbnailsToRefresh = mSnapshotViewMap.clone();
SparseArray<TaskThumbnailViewDeprecated> thumbnailsToRefresh = mSnapshotViewMap.clone();
if (thumbnailDatas != null) {
for (Task task : mTasks) {
int key = task.key.id;
TaskThumbnailView thumbnailView = thumbnailsToRefresh.get(key);
TaskThumbnailViewDeprecated thumbnailView = thumbnailsToRefresh.get(key);
ThumbnailData thumbnailData = thumbnailDatas.get(key);
if (thumbnailView != null && thumbnailData != null) {
thumbnailView.setThumbnail(task, thumbnailData);
@@ -388,8 +390,9 @@ public class DesktopTaskView extends TaskView {
}
@Override
public TaskThumbnailView[] getThumbnails() {
TaskThumbnailView[] thumbnails = new TaskThumbnailView[mSnapshotViewMap.size()];
public TaskThumbnailViewDeprecated[] getThumbnails() {
TaskThumbnailViewDeprecated[] thumbnails =
new TaskThumbnailViewDeprecated[mSnapshotViewMap.size()];
for (int i = 0; i < thumbnails.length; i++) {
thumbnails[i] = mSnapshotViewMap.valueAt(i);
}
@@ -402,7 +405,7 @@ public class DesktopTaskView extends TaskView {
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
for (Task task : mTasks) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.setThumbnail(task, null);
}
@@ -453,7 +456,7 @@ public class DesktopTaskView extends TaskView {
int thumbWidth = (int) (taskSize.width() * scaleWidth);
int thumbHeight = (int) (taskSize.height() * scaleHeight);
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY));
@@ -495,7 +498,7 @@ public class DesktopTaskView extends TaskView {
mBackgroundView.setVisibility(VISIBLE);
}
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.valueAt(i);
thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
}
updateSnapshotRadius();
@@ -31,7 +31,7 @@ import androidx.annotation.Nullable;
/**
* A child view of {@link com.android.quickstep.views.FloatingTaskView} to draw the thumbnail in a
* rounded corner frame. While the purpose of this class sounds similar to
* {@link TaskThumbnailView}, it doesn't need a lot of complex logic in {@link TaskThumbnailView}
* {@link TaskThumbnailViewDeprecated}, it doesn't need a lot of complex logic in {@link TaskThumbnailViewDeprecated}
* in relation to moving with {@link RecentsView}.
*/
public class FloatingTaskThumbnailView extends View {
@@ -60,7 +60,8 @@ public class GroupedTaskView extends TaskView {
@Nullable
private Task mSecondaryTask;
private TaskThumbnailView mSnapshotView2;
// TODO(b/336612373): Support new TTV for GroupedTaskView
private TaskThumbnailViewDeprecated mSnapshotView2;
private TaskViewIcon mIconView2;
@Nullable
private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
@@ -68,7 +69,8 @@ public class GroupedTaskView extends TaskView {
private CancellableTask mIconLoadRequest2;
private final float[] mIcon2CenterCoords = new float[2];
private TransformingTouchDelegate mIcon2TouchDelegate;
@Nullable private SplitBounds mSplitBoundsConfig;
@Nullable
private SplitBounds mSplitBoundsConfig;
private final DigitalWellBeingToast mDigitalWellBeingToast2;
public GroupedTaskView(Context context) {
@@ -91,13 +93,17 @@ public class GroupedTaskView extends TaskView {
return Unit.INSTANCE;
}
bounds.set(
Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
Math.min(mTaskThumbnailViewDeprecated.getLeft() + Math.round(
mTaskThumbnailViewDeprecated.getTranslationX()),
mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
Math.min(mTaskThumbnailViewDeprecated.getTop() + Math.round(
mTaskThumbnailViewDeprecated.getTranslationY()),
mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
Math.max(mTaskThumbnailViewDeprecated.getRight() + Math.round(
mTaskThumbnailViewDeprecated.getTranslationX()),
mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
Math.max(mTaskThumbnailViewDeprecated.getBottom() + Math.round(
mTaskThumbnailViewDeprecated.getTranslationY()),
mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
return Unit.INSTANCE;
}
@@ -130,7 +136,7 @@ public class GroupedTaskView extends TaskView {
if (mSplitBoundsConfig == null) {
return;
}
mSnapshotView.getPreviewPositionHelper().setSplitBounds(
mTaskThumbnailViewDeprecated.getPreviewPositionHelper().setSplitBounds(
convertLauncherSplitBoundsToShell(splitBoundsConfig),
PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT);
mSnapshotView2.getPreviewPositionHelper().setSplitBounds(
@@ -304,8 +310,8 @@ public class GroupedTaskView extends TaskView {
}
@Override
public TaskThumbnailView[] getThumbnails() {
return new TaskThumbnailView[]{mSnapshotView, mSnapshotView2};
public TaskThumbnailViewDeprecated[] getThumbnails() {
return new TaskThumbnailViewDeprecated[]{mTaskThumbnailViewDeprecated, mSnapshotView2};
}
@Override
@@ -349,20 +355,24 @@ public class GroupedTaskView extends TaskView {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) {
if (mSplitBoundsConfig == null || mTaskThumbnailViewDeprecated == null
|| mSnapshotView2 == null) {
return;
}
int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
if (initSplitTaskId == INVALID_TASK_ID) {
getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(
mTaskThumbnailViewDeprecated,
mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
mContainer.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
// Should we be having a separate translation step apart from the measuring above?
// The following only applies to large screen for now, but for future reference
// we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
// translation directions
mSnapshotView.applySplitSelectTranslateX(mSnapshotView.getTranslationX());
mSnapshotView.applySplitSelectTranslateY(mSnapshotView.getTranslationY());
mTaskThumbnailViewDeprecated.applySplitSelectTranslateX(
mTaskThumbnailViewDeprecated.getTranslationX());
mTaskThumbnailViewDeprecated.applySplitSelectTranslateY(
mTaskThumbnailViewDeprecated.getTranslationY());
mSnapshotView2.applySplitSelectTranslateX(mSnapshotView2.getTranslationX());
mSnapshotView2.applySplitSelectTranslateY(mSnapshotView2.getTranslationY());
} else {
@@ -446,8 +456,9 @@ public class GroupedTaskView extends TaskView {
mSplitBoundsConfig);
} else {
getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
taskIconHeight, mSnapshotView.getMeasuredWidth(),
mSnapshotView.getMeasuredHeight(), getMeasuredHeight(), getMeasuredWidth(),
taskIconHeight, mTaskThumbnailViewDeprecated.getMeasuredWidth(),
mTaskThumbnailViewDeprecated.getMeasuredHeight(), getMeasuredHeight(),
getMeasuredWidth(),
isRtl, deviceProfile, mSplitBoundsConfig);
}
}
@@ -510,12 +521,12 @@ public class GroupedTaskView extends TaskView {
@Override
void setThumbnailVisibility(int visibility, int taskId) {
if (visibility == VISIBLE) {
mSnapshotView.setVisibility(visibility);
mTaskThumbnailViewDeprecated.setVisibility(visibility);
mDigitalWellBeingToast.setBannerVisibility(visibility);
mSnapshotView2.setVisibility(visibility);
mDigitalWellBeingToast2.setBannerVisibility(visibility);
} else if (taskId == getTaskIds()[0]) {
mSnapshotView.setVisibility(visibility);
mTaskThumbnailViewDeprecated.setVisibility(visibility);
mDigitalWellBeingToast.setBannerVisibility(visibility);
} else {
mSnapshotView2.setVisibility(visibility);
@@ -130,6 +130,7 @@ import androidx.core.graphics.ColorUtils;
import com.android.internal.jank.Cuj;
import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.PagedView;
@@ -1045,8 +1046,9 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
continue;
}
Task task = taskAttributes.getTask();
TaskThumbnailView taskThumbnailView = taskAttributes.getThumbnailView();
taskThumbnailView.setThumbnail(task, thumbnail, refreshNow);
TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
taskAttributes.getThumbnailView();
taskThumbnailViewDeprecated.setThumbnail(task, thumbnail, refreshNow);
// thumbnailData can contain 1-2 ids, but they should correspond to the same
// TaskView, so overwriting is ok
updatedTaskView = taskView;
@@ -1833,7 +1835,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
// the full list of tasks to taskViews
newRunningTaskView = getTaskViewByTaskIds(runningTaskId);
if (newRunningTaskView != null) {
mRunningTaskViewId = newRunningTaskView.getTaskViewId();
setRunningTaskViewId(newRunningTaskView.getTaskViewId());
} else {
if (mActiveGestureRunningTasks != null) {
// This will update mRunningTaskViewId and create a stub view if necessary.
@@ -1842,7 +1844,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
// the current running task is excludedFromRecents.)
showCurrentTask(mActiveGestureRunningTasks);
} else {
mRunningTaskViewId = INVALID_TASK_ID;
setRunningTaskViewId(INVALID_TASK_ID);
}
}
}
@@ -2842,7 +2844,23 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
setRunningTaskViewShowScreenshot(true);
setRunningTaskHidden(false);
}
setRunningTaskViewId(runningTaskViewId);
}
private void setRunningTaskViewId(int runningTaskViewId) {
int prevRunningTaskViewId = mRunningTaskViewId;
mRunningTaskViewId = runningTaskViewId;
if (Flags.enableRefactorTaskThumbnail()) {
TaskView previousRunningTaskView = getTaskViewFromTaskViewId(prevRunningTaskViewId);
if (previousRunningTaskView != null) {
previousRunningTaskView.notifyIsRunningTaskUpdated();
}
TaskView newRunningTaskView = getTaskViewFromTaskViewId(runningTaskViewId);
if (newRunningTaskView != null) {
newRunningTaskView.notifyIsRunningTaskUpdated();
}
}
}
private int getTaskViewIdFromTaskId(int taskId) {
@@ -4762,7 +4780,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
mSplitSelectStateController.getInitialTaskId();
TaskIdAttributeContainer taskIdAttributeContainer = mSplitHiddenTaskView
.getTaskIdAttributeContainers()[primaryTaskSelected ? 1 : 0];
TaskThumbnailView thumbnail = taskIdAttributeContainer.getThumbnailView();
TaskThumbnailViewDeprecated thumbnail = taskIdAttributeContainer.getThumbnailView();
mSplitSelectStateController.getSplitAnimationController()
.addInitialSplitFromPair(taskIdAttributeContainer, builder,
mContainer.getDeviceProfile(),
@@ -5865,7 +5883,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
ThumbnailData td =
mRecentsAnimationController.screenshotTask(container.getTask().key.id);
TaskThumbnailView thumbnailView = container.getThumbnailView();
TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailView();
if (td != null) {
thumbnailView.setThumbnail(container.getTask(), td);
} else {
@@ -22,7 +22,7 @@ import static com.android.launcher3.testing.shared.TestProtocol.TEST_TAPL_OVERVI
import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
import static com.android.quickstep.views.TaskThumbnailViewDeprecated.DIM_ALPHA;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -62,61 +62,66 @@ import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
/**
* A task in the Recents view.
*
* @deprecated This class will be replaced by the new [TaskThumbnailView].
*/
public class TaskThumbnailView extends View {
@Deprecated
public class TaskThumbnailViewDeprecated extends View {
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
new FloatProperty<TaskThumbnailView>("dimAlpha") {
public static final Property<TaskThumbnailViewDeprecated, Float> DIM_ALPHA =
new FloatProperty<TaskThumbnailViewDeprecated>("dimAlpha") {
@Override
public void setValue(TaskThumbnailView thumbnail, float dimAlpha) {
public void setValue(TaskThumbnailViewDeprecated thumbnail, float dimAlpha) {
thumbnail.setDimAlpha(dimAlpha);
}
@Override
public Float get(TaskThumbnailView thumbnailView) {
public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mDimAlpha;
}
};
public static final Property<TaskThumbnailView, Float> SPLASH_ALPHA =
new FloatProperty<TaskThumbnailView>("splashAlpha") {
public static final Property<TaskThumbnailViewDeprecated, Float> SPLASH_ALPHA =
new FloatProperty<TaskThumbnailViewDeprecated>("splashAlpha") {
@Override
public void setValue(TaskThumbnailView thumbnail, float splashAlpha) {
public void setValue(TaskThumbnailViewDeprecated thumbnail, float splashAlpha) {
thumbnail.setSplashAlpha(splashAlpha);
}
@Override
public Float get(TaskThumbnailView thumbnailView) {
public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mSplashAlpha / 255f;
}
};
/** Use to animate thumbnail translationX while first app in split selection is initiated */
public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_X =
new FloatProperty<TaskThumbnailView>("splitSelectTranslateX") {
public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_X =
new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateX") {
@Override
public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateX) {
public void setValue(TaskThumbnailViewDeprecated thumbnail,
float splitSelectTranslateX) {
thumbnail.applySplitSelectTranslateX(splitSelectTranslateX);
}
@Override
public Float get(TaskThumbnailView thumbnailView) {
public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mSplitSelectTranslateX;
}
};
/** Use to animate thumbnail translationY while first app in split selection is initiated */
public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_Y =
new FloatProperty<TaskThumbnailView>("splitSelectTranslateY") {
public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_Y =
new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateY") {
@Override
public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateY) {
public void setValue(TaskThumbnailViewDeprecated thumbnail,
float splitSelectTranslateY) {
thumbnail.applySplitSelectTranslateY(splitSelectTranslateY);
}
@Override
public Float get(TaskThumbnailView thumbnailView) {
public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mSplitSelectTranslateY;
}
};
@@ -156,15 +161,16 @@ public class TaskThumbnailView extends View {
private float mSplitSelectTranslateX;
private float mSplitSelectTranslateY;
public TaskThumbnailView(Context context) {
public TaskThumbnailViewDeprecated(Context context) {
this(context, null);
}
public TaskThumbnailView(Context context, @Nullable AttributeSet attrs) {
public TaskThumbnailViewDeprecated(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TaskThumbnailView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
public TaskThumbnailViewDeprecated(Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
@@ -180,7 +186,6 @@ public class TaskThumbnailView extends View {
/**
* Updates the thumbnail to draw the provided task
* @param task
*/
public void bind(Task task) {
getTaskOverlay().reset();
@@ -194,6 +199,7 @@ public class TaskThumbnailView extends View {
/**
* Updates the thumbnail.
*
* @param refreshNow whether the {@code thumbnailData} will be used to redraw immediately.
* In most cases, we use the {@link #setThumbnail(Task, ThumbnailData)}
* version with {@code refreshNow} is true. The only exception is
@@ -227,6 +233,7 @@ public class TaskThumbnailView extends View {
/**
* Updates the shader, paint, matrix to redraw.
*
* @param shouldRefreshOverlay whether to re-initialize overlay
*/
private void refresh(boolean shouldRefreshOverlay) {
@@ -253,7 +260,6 @@ public class TaskThumbnailView extends View {
* <p>
* If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
* extracted background color.
*
*/
public void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
@@ -286,6 +292,7 @@ public class TaskThumbnailView extends View {
/**
* Get the scaled insets that are being used to draw the task view. This is a subsection of
* the full snapshot.
*
* @return the insets in snapshot bitmap coordinates.
*/
@RequiresApi(api = Build.VERSION_CODES.Q)
@@ -25,6 +25,7 @@ import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
@@ -106,6 +107,8 @@ import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.task.thumbnail.TaskThumbnail;
import com.android.quickstep.task.thumbnail.TaskThumbnailView;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.BorderAnimator;
import com.android.quickstep.util.RecentsOrientedState;
@@ -127,6 +130,7 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* A task in the Recents view.
*/
@@ -318,13 +322,15 @@ public class TaskView extends FrameLayout implements Reusable {
@Override
public Float get(TaskView taskView) {
return taskView.mSnapshotView.getScaleX();
return taskView.mTaskThumbnailViewDeprecated.getScaleX();
}
};
@Nullable
protected Task mTask;
protected TaskThumbnailView mSnapshotView;
@Nullable // can be null when enableRefactorTaskThumbnail() == true
protected TaskThumbnailViewDeprecated mTaskThumbnailViewDeprecated;
protected TaskThumbnailView mTaskThumbnailView;
protected TaskViewIcon mIconView;
protected final DigitalWellBeingToast mDigitalWellBeingToast;
protected float mFullscreenProgress;
@@ -463,10 +469,11 @@ public class TaskView extends FrameLayout implements Reusable {
}
protected Unit updateBorderBounds(@NonNull Rect bounds) {
bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()));
View snapshotView = getSnapshotView();
bounds.set(snapshotView.getLeft() + Math.round(snapshotView.getTranslationX()),
snapshotView.getTop() + Math.round(snapshotView.getTranslationY()),
snapshotView.getRight() + Math.round(snapshotView.getTranslationX()),
snapshotView.getBottom() + Math.round(snapshotView.getTranslationY()));
return Unit.INSTANCE;
}
@@ -478,6 +485,17 @@ public class TaskView extends FrameLayout implements Reusable {
return mTaskViewId;
}
/**
* Updates [TaskThumbnailView] to reflect the latest [Task] state (i.e., task isRunning).
*/
public void notifyIsRunningTaskUpdated() {
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
if (mTask != null) {
bindTaskThumbnailView();
}
}
/**
* Builds proto for logging
*/
@@ -515,7 +533,14 @@ public class TaskView extends FrameLayout implements Reusable {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSnapshotView = findViewById(R.id.snapshot);
mTaskThumbnailViewDeprecated = findViewById(R.id.snapshot);
if (enableRefactorTaskThumbnail()) {
mTaskThumbnailView = new TaskThumbnailView(mContext);
mTaskThumbnailView.setLayoutParams(mTaskThumbnailViewDeprecated.getLayoutParams());
int indexOfSnapshotView = indexOfChild(mTaskThumbnailViewDeprecated);
addView(mTaskThumbnailView, indexOfSnapshotView);
mTaskThumbnailViewDeprecated.setVisibility(View.GONE);
}
ViewStub iconViewStub = findViewById(R.id.icon);
if (enableOverviewIconMenu()) {
iconViewStub.setLayoutResource(R.layout.icon_app_chip_view);
@@ -650,12 +675,23 @@ public class TaskView extends FrameLayout implements Reusable {
cancelPendingLoadTasks();
mTask = task;
mTaskIdContainer[0] = mTask.key.id;
mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView, mIconView,
mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task,
mTaskThumbnailViewDeprecated, mIconView,
STAGE_POSITION_UNDEFINED);
mSnapshotView.bind(task);
if (enableRefactorTaskThumbnail()) {
bindTaskThumbnailView();
} else {
mTaskThumbnailViewDeprecated.bind(task);
}
setOrientationState(orientedState);
}
private void bindTaskThumbnailView() {
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
mTaskThumbnailView.getViewModel().bind(new TaskThumbnail(mTask, isRunningTask()));
}
/**
* Sets up an on-click listener and the visibility for show_windows icon on top of the task.
*/
@@ -745,25 +781,29 @@ public class TaskView extends FrameLayout implements Reusable {
return null;
}
public TaskThumbnailView getThumbnail() {
return mSnapshotView;
public TaskThumbnailViewDeprecated getThumbnail() {
return mTaskThumbnailViewDeprecated;
}
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
if (enableRefactorTaskThumbnail()) {
// TODO(b/334825222) add thumbnail logic
return;
}
if (mTask != null && thumbnailDatas != null) {
final ThumbnailData thumbnailData = thumbnailDatas.get(mTask.key.id);
if (thumbnailData != null) {
mSnapshotView.setThumbnail(mTask, thumbnailData);
mTaskThumbnailViewDeprecated.setThumbnail(mTask, thumbnailData);
return;
}
}
mSnapshotView.refresh();
mTaskThumbnailViewDeprecated.refresh();
}
/** TODO(b/197033698) Remove all usages of above method and migrate to this one */
public TaskThumbnailView[] getThumbnails() {
return new TaskThumbnailView[]{mSnapshotView};
public TaskThumbnailViewDeprecated[] getThumbnails() {
return new TaskThumbnailViewDeprecated[]{mTaskThumbnailViewDeprecated};
}
public TaskViewIcon getIconView() {
@@ -948,7 +988,10 @@ public class TaskView extends FrameLayout implements Reusable {
if (isQuickswitch) {
opts.setFreezeRecentTasksReordering();
}
opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView());
// TODO(b/334826842) add splash functionality to new TTV
if (!enableRefactorTaskThumbnail()) {
opts.setDisableStartingWindow(mTaskThumbnailViewDeprecated.shouldShowSplashView());
}
Task.TaskKey key = mTask.key;
UI_HELPER_EXECUTOR.execute(() -> {
if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
@@ -1069,7 +1112,10 @@ public class TaskView extends FrameLayout implements Reusable {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
mTask, thumbnail -> {
mSnapshotView.setThumbnail(mTask, thumbnail);
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334825222) add thumbnail state
mTaskThumbnailViewDeprecated.setThumbnail(mTask, thumbnail);
}
});
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
@@ -1087,7 +1133,10 @@ public class TaskView extends FrameLayout implements Reusable {
}
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
mSnapshotView.setThumbnail(null, null);
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334825222) add thumbnail state
mTaskThumbnailViewDeprecated.setThumbnail(null, null);
}
// Reset the task thumbnail reference as well (it will be fetched from the cache or
// reloaded next time we need it)
mTask.thumbnail = null;
@@ -1195,11 +1244,15 @@ public class TaskView extends FrameLayout implements Reusable {
// TODO(b/271468547), we should default to setting trasnlations only on the snapshot instead
// of a hybrid of both margins and translations
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
LayoutParams snapshotParams = (LayoutParams) getSnapshotView().getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
mSnapshotView.setLayoutParams(snapshotParams);
getSnapshotView().setLayoutParams(snapshotParams);
mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
// TODO(b/335606129) Investigate the usage of [TaskOverlay] in the new TaskThumbnailView.
// and if it's still necessary we should support that in the new TTV class.
if (!enableRefactorTaskThumbnail()) {
mTaskThumbnailViewDeprecated.getTaskOverlay().updateOrientationState(orientationState);
}
mDigitalWellBeingToast.initialize(mTask);
}
@@ -1288,7 +1341,10 @@ public class TaskView extends FrameLayout implements Reusable {
setAlpha(mStableAlpha);
setIconScaleAndDim(1);
setColorTint(0, 0);
mSnapshotView.resetViewTransforms();
if (!enableRefactorTaskThumbnail()) {
// TODO(b/335399428) add split select functionality to new TTV
mTaskThumbnailViewDeprecated.resetViewTransforms();
}
}
public void setStableAlpha(float parentAlpha) {
@@ -1301,7 +1357,12 @@ public class TaskView extends FrameLayout implements Reusable {
resetPersistentViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
mSnapshotView.setThumbnail(mTask, null);
// TODO(b/334825222): Implement thumbnail/snapshot for the new [TaskThumbnailView].
if (enableRefactorTaskThumbnail()) {
notifyIsRunningTaskUpdated();
} else {
mTaskThumbnailViewDeprecated.setThumbnail(mTask, null);
}
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
mBorderEnabled = false;
@@ -1316,10 +1377,10 @@ public class TaskView extends FrameLayout implements Reusable {
super.onLayout(changed, left, top, right, bottom);
if (mContainer.getDeviceProfile().isTablet) {
setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
setPivotY(mSnapshotView.getTop());
setPivotY(getSnapshotView().getTop());
} else {
setPivotX((right - left) * 0.5f);
setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
setPivotY(getSnapshotView().getTop() + getSnapshotView().getHeight() * 0.5f);
}
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
@@ -1387,11 +1448,17 @@ public class TaskView extends FrameLayout implements Reusable {
}
protected void applyThumbnailSplashAlpha() {
mSnapshotView.setSplashAlpha(mTaskThumbnailSplashAlpha);
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334826842) add splash functionality to new TTV
mTaskThumbnailViewDeprecated.setSplashAlpha(mTaskThumbnailSplashAlpha);
}
}
protected void refreshTaskThumbnailSplash() {
mSnapshotView.refreshSplashView();
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334826842) add splash functionality to new TTV
mTaskThumbnailViewDeprecated.refreshSplashView();
}
}
private void setSplitSelectTranslationX(float x) {
@@ -1670,7 +1737,11 @@ public class TaskView extends FrameLayout implements Reusable {
progress = Utilities.boundToRange(progress, 0, 1);
mFullscreenProgress = progress;
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
mSnapshotView.getTaskOverlay().setFullscreenProgress(progress);
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334826840) Add corner rounding to new TTV
mTaskThumbnailViewDeprecated.getTaskOverlay().setFullscreenProgress(progress);
}
RecentsView recentsView = mContainer.getOverviewPanel();
// Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
// oversized and banner would look disproportionately large.
@@ -1683,7 +1754,10 @@ public class TaskView extends FrameLayout implements Reusable {
protected void updateSnapshotRadius() {
updateCurrentFullscreenParams();
mSnapshotView.setFullscreenParams(mCurrentFullscreenParams);
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334826840) Add corner rounding to new TTV
mTaskThumbnailViewDeprecated.setFullscreenParams(mCurrentFullscreenParams);
}
}
void updateCurrentFullscreenParams() {
@@ -1796,7 +1870,11 @@ public class TaskView extends FrameLayout implements Reusable {
}
public void setOverlayEnabled(boolean overlayEnabled) {
mSnapshotView.setOverlayEnabled(overlayEnabled);
// TODO(b/335606129) Investigate the usage of [TaskOverlay] in the new TaskThumbnailView.
// and if it's still necessary we should support that in the new TTV class.
if (!enableRefactorTaskThumbnail()) {
mTaskThumbnailViewDeprecated.setOverlayEnabled(overlayEnabled);
}
}
public void initiateSplitSelect(SplitPositionOption splitPositionOption) {
@@ -1808,7 +1886,10 @@ public class TaskView extends FrameLayout implements Reusable {
* Set a color tint on the snapshot and supporting views.
*/
public void setColorTint(float amount, int tintColor) {
mSnapshotView.setDimAlpha(amount);
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334832108) Add scrim to new TTV
mTaskThumbnailViewDeprecated.setDimAlpha(amount);
}
mIconView.setIconColorTint(tintColor, amount);
mDigitalWellBeingToast.setBannerColorTint(tintColor, amount);
}
@@ -1834,6 +1915,10 @@ public class TaskView extends FrameLayout implements Reusable {
}
}
private View getSnapshotView() {
return enableRefactorTaskThumbnail() ? mTaskThumbnailView : mTaskThumbnailViewDeprecated;
}
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
@@ -1878,7 +1963,7 @@ public class TaskView extends FrameLayout implements Reusable {
}
public class TaskIdAttributeContainer {
private final TaskThumbnailView mThumbnailView;
private final TaskThumbnailViewDeprecated mThumbnailView;
private final Task mTask;
private final TaskViewIcon mIconView;
/** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
@@ -1886,7 +1971,7 @@ public class TaskView extends FrameLayout implements Reusable {
@IdRes
private final int mA11yNodeId;
public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
public TaskIdAttributeContainer(Task task, TaskThumbnailViewDeprecated thumbnailView,
TaskViewIcon iconView, int stagePosition) {
this.mTask = task;
this.mThumbnailView = thumbnailView;
@@ -1896,7 +1981,7 @@ public class TaskView extends FrameLayout implements Reusable {
R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
}
public TaskThumbnailView getThumbnailView() {
public TaskThumbnailViewDeprecated getThumbnailView() {
return mThumbnailView;
}