diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java index 0eb8775211..26ca06af31 100644 --- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java +++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java @@ -56,7 +56,7 @@ import com.android.launcher3.views.ArrowTipView; import com.android.quickstep.util.AssistContentRequester; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.views.GoOverviewActionsView; -import com.android.quickstep.views.TaskThumbnailViewDeprecated; +import com.android.quickstep.views.TaskView.TaskContainer; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -101,8 +101,8 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { /** * Create a new overlay instance for the given View */ - public TaskOverlayGo createOverlay(TaskThumbnailViewDeprecated thumbnailView) { - return new TaskOverlayGo(thumbnailView, mContentRequester); + public TaskOverlayGo createOverlay(TaskContainer taskContainer) { + return new TaskOverlayGo(taskContainer, mContentRequester); } /** @@ -120,9 +120,9 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { private OverlayDialogGo mDialog; private ArrowTipView mArrowTipView; - private TaskOverlayGo(TaskThumbnailViewDeprecated taskThumbnailView, + private TaskOverlayGo(TaskContainer taskContainer, AssistContentRequester assistContentRequester) { - super(taskThumbnailView); + super(taskContainer); mFactoryContentRequester = assistContentRequester; mSharedPreferences = LauncherPrefs.getPrefs(mApplicationContext); } @@ -148,7 +148,8 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { // Disable Overview Actions for Work Profile apps boolean isManagedProfileTask = UserManager.get(mApplicationContext).isManagedProfile(task.key.userId); - boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot() && !isManagedProfileTask; + boolean isAllowedByPolicy = mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot() + && !isManagedProfileTask; getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task)); mTaskPackageName = task.key.getPackageName(); mSharedPreferences = LauncherPrefs.getPrefs(mApplicationContext); @@ -162,8 +163,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { int taskId = task.key.id; mFactoryContentRequester.requestAssistContent(taskId, this::onAssistContentReceived); - RecentsOrientedState orientedState = - mThumbnailView.getTaskView().getRecentsView().getPagedViewOrientedState(); + RecentsOrientedState orientedState = mTaskContainer.getTaskView().getOrientedState(); boolean isInLandscape = orientedState.getDisplayRotation() != ROTATION_0; // show tooltips in portrait mode only diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index d0c494cbd5..2b68b52932 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -269,8 +269,8 @@ public class TaskbarUIController { foundTaskView, foundTask, taskContainer.getIconView().getDrawable(), - taskContainer.getThumbnailView(), - taskContainer.getThumbnailView().getThumbnail(), + taskContainer.getThumbnailViewDeprecated(), + taskContainer.getThumbnailViewDeprecated().getThumbnail(), null /* intent */, null /* user */, info); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index 1a98db1f29..93e4fbdc00 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -151,7 +151,7 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll int sysuiFlags = 0; TaskView tv = mOverviewPanel.getTaskViewAt(0); if (tv != null) { - sysuiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags(); + sysuiFlags = tv.getFirstThumbnailViewDeprecated().getSysUiStatusNavFlags(); } mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags); } else { diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index 26b528caab..4bc3c1661e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -252,7 +252,7 @@ public abstract class TaskViewTouchController 1 - UPDATE_SYSUI_FLAGS_THRESHOLD; boolean quickswitchThresholdPassed = centermostTask != runningTask; @@ -1478,7 +1477,7 @@ public abstract class AbsSwipeUpHandler( R.drawable.ic_caption_desktop_button_foreground, R.string.recent_task_option_desktop, container, - mTaskContainer.itemInfo, - mTaskContainer.taskView, + taskContainer.itemInfo, + taskContainer.taskView, abstractFloatingViewHelper ) { override fun onClick(view: View) { dismissTaskMenuView() - val recentsView = mTarget!!.getOverviewPanel>() - recentsView.moveTaskToDesktop(mTaskContainer) { + val recentsView = mTarget.getOverviewPanel>() + recentsView.moveTaskToDesktop(taskContainer) { mTarget.statsLogManager .logger() - .withItemInfo(mTaskContainer.itemInfo) + .withItemInfo(taskContainer.itemInfo) .log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP) } } diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index 1a46fb6470..b183ae392f 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -80,8 +80,9 @@ public class TaskOverlayFactory implements ResourceBasedOverride { return shortcuts; } - public TaskOverlay createOverlay(TaskThumbnailViewDeprecated thumbnailView) { - return new TaskOverlay(thumbnailView); + /** Creates a {@link TaskOverlay} associated with the provide {@link TaskContainer}. */ + public TaskOverlay createOverlay(TaskContainer taskContainer) { + return new TaskOverlay<>(taskContainer); } /** @@ -124,28 +125,29 @@ public class TaskOverlayFactory implements ResourceBasedOverride { public static class TaskOverlay { protected final Context mApplicationContext; - protected final TaskThumbnailViewDeprecated mThumbnailView; + protected final TaskContainer mTaskContainer; private T mActionsView; protected ImageActionsApi mImageApi; - protected TaskOverlay(TaskThumbnailViewDeprecated taskThumbnailViewDeprecated) { - mApplicationContext = taskThumbnailViewDeprecated.getContext().getApplicationContext(); - mThumbnailView = taskThumbnailViewDeprecated; + protected TaskOverlay(TaskContainer taskContainer) { + mApplicationContext = taskContainer.getTaskView().getContext().getApplicationContext(); + mTaskContainer = taskContainer; mImageApi = new ImageActionsApi( - mApplicationContext, mThumbnailView::getThumbnail); + mApplicationContext, mTaskContainer.getThumbnailViewDeprecated()::getThumbnail); } protected T getActionsView() { if (mActionsView == null) { - mActionsView = BaseActivity.fromContext(mThumbnailView.getContext()).findViewById( + mActionsView = BaseActivity.fromContext( + mTaskContainer.getThumbnailViewDeprecated().getContext()).findViewById( R.id.overview_actions_view); } return mActionsView; } public TaskThumbnailViewDeprecated getThumbnailView() { - return mThumbnailView; + return mTaskContainer.getThumbnailViewDeprecated(); } /** @@ -157,7 +159,8 @@ public class TaskOverlayFactory implements ResourceBasedOverride { if (thumbnail != null) { getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); - boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot(); + boolean isAllowedByPolicy = + mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot(); getActionsView().setCallbacks(new OverlayUICallbacksImpl(isAllowedByPolicy, task)); } } @@ -168,7 +171,8 @@ public class TaskOverlayFactory implements ResourceBasedOverride { * @param callback callback to run, after switching to screenshot */ public void endLiveTileMode(@NonNull Runnable callback) { - RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView(); + RecentsView recentsView = + mTaskContainer.getThumbnailViewDeprecated().getTaskView().getRecentsView(); // Task has already been dismissed if (recentsView == null) return; recentsView.switchToScreenshot( @@ -181,8 +185,8 @@ public class TaskOverlayFactory implements ResourceBasedOverride { */ @SuppressLint("NewApi") protected void saveScreenshot(Task task) { - if (mThumbnailView.isRealSnapshot()) { - mImageApi.saveScreenshot(mThumbnailView.getThumbnail(), + if (mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot()) { + mImageApi.saveScreenshot(mTaskContainer.getThumbnailViewDeprecated().getThumbnail(), getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key); } else { showBlockedByPolicyMessage(); @@ -190,14 +194,17 @@ public class TaskOverlayFactory implements ResourceBasedOverride { } protected void enterSplitSelect() { - RecentsView overviewPanel = mThumbnailView.getTaskView().getRecentsView(); + RecentsView overviewPanel = + mTaskContainer.getThumbnailViewDeprecated().getTaskView().getRecentsView(); // Task has already been dismissed if (overviewPanel == null) return; - overviewPanel.initiateSplitSelect(mThumbnailView.getTaskView()); + overviewPanel.initiateSplitSelect( + mTaskContainer.getThumbnailViewDeprecated().getTaskView()); } protected void saveAppPair() { - GroupedTaskView taskView = (GroupedTaskView) mThumbnailView.getTaskView(); + GroupedTaskView taskView = + (GroupedTaskView) mTaskContainer.getThumbnailViewDeprecated().getTaskView(); taskView.getRecentsView().getSplitSelectController().getAppPairsController() .saveAppPair(taskView); } @@ -243,10 +250,11 @@ public class TaskOverlayFactory implements ResourceBasedOverride { */ public Rect getTaskSnapshotBounds() { int[] location = new int[2]; - mThumbnailView.getLocationOnScreen(location); + mTaskContainer.getThumbnailViewDeprecated().getLocationOnScreen(location); - return new Rect(location[0], location[1], mThumbnailView.getWidth() + location[0], - mThumbnailView.getHeight() + location[1]); + return new Rect(location[0], location[1], + mTaskContainer.getThumbnailViewDeprecated().getWidth() + location[0], + mTaskContainer.getThumbnailViewDeprecated().getHeight() + location[1]); } /** @@ -256,7 +264,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride { */ @RequiresApi(api = Build.VERSION_CODES.Q) public Insets getTaskSnapshotInsets() { - return mThumbnailView.getScaledInsets(); + return mTaskContainer.getThumbnailViewDeprecated().getScaledInsets(); } /** @@ -267,17 +275,21 @@ public class TaskOverlayFactory implements ResourceBasedOverride { protected void showBlockedByPolicyMessage() { ActivityContext activityContext = ActivityContext.lookupContext( - mThumbnailView.getContext()); + mTaskContainer.getThumbnailViewDeprecated().getContext()); String message = activityContext.getStringCache() != null ? activityContext.getStringCache().disabledByAdminMessage - : mThumbnailView.getContext().getString(R.string.blocked_by_policy); + : mTaskContainer.getThumbnailViewDeprecated().getContext().getString( + R.string.blocked_by_policy); - Snackbar.show(BaseActivity.fromContext(mThumbnailView.getContext()), message, null); + Snackbar.show(BaseActivity.fromContext( + mTaskContainer.getThumbnailViewDeprecated().getContext()), message, null); } /** Called when the snapshot has updated its full screen drawing parameters. */ - public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) { - } + public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {} + + /** Sets visibility for the overlay associated elements. */ + public void setVisibility(int visibility) {} private class ScreenshotSystemShortcut extends SystemShortcut { @@ -292,7 +304,8 @@ public class TaskOverlayFactory implements ResourceBasedOverride { @Override public void onClick(View view) { - saveScreenshot(mThumbnailView.getTaskView().getFirstTask()); + saveScreenshot( + mTaskContainer.getThumbnailViewDeprecated().getTaskView().getFirstTask()); dismissTaskMenuView(); } } diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index 537f4321d2..4b5c826fcf 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -128,7 +128,8 @@ public interface TaskShortcutFactory { public SplitSelectSystemShortcut(RecentsViewContainer container, TaskView taskView, SplitPositionOption option) { - super(option.iconResId, option.textResId, container, taskView.getItemInfo(), taskView); + super(option.iconResId, option.textResId, container, taskView.getFirstItemInfo(), + taskView); mTaskView = taskView; mSplitPositionOption = option; } @@ -149,8 +150,8 @@ public interface TaskShortcutFactory { public SaveAppPairSystemShortcut(RecentsViewContainer container, GroupedTaskView taskView, int iconResId) { - super(iconResId, R.string.save_app_pair, container, - taskView.getItemInfo(), taskView); + super(iconResId, R.string.save_app_pair, container, taskView.getFirstItemInfo(), + taskView); mTaskView = taskView; } @@ -180,7 +181,7 @@ public interface TaskShortcutFactory { mHandler = new Handler(Looper.getMainLooper()); mTaskView = taskContainer.getTaskView(); mRecentsView = container.getOverviewPanel(); - mThumbnailView = taskContainer.getThumbnailView(); + mThumbnailView = taskContainer.getThumbnailViewDeprecated(); } @Override @@ -240,7 +241,7 @@ public interface TaskShortcutFactory { overridePendingAppTransitionMultiThumbFuture( future, animStartedListener, mHandler, true /* scaleUp */, taskKey.displayId); - mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo()) + mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getFirstItemInfo()) .log(mLauncherEvent); } } @@ -424,7 +425,7 @@ public interface TaskShortcutFactory { mTaskView.getFirstTask().key.id); } dismissTaskMenuView(); - mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo()) + mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getFirstItemInfo()) .log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP); } } @@ -469,10 +470,8 @@ public interface TaskShortcutFactory { } } - SystemShortcut screenshotShortcut = - taskContainer.getThumbnailView().getTaskOverlay() - .getScreenshotShortcut(container, taskContainer.getItemInfo(), - taskContainer.getTaskView()); + SystemShortcut screenshotShortcut = taskContainer.getOverlay().getScreenshotShortcut( + container, taskContainer.getItemInfo(), taskContainer.getTaskView()); return createSingletonShortcutList(screenshotShortcut); } @@ -503,9 +502,8 @@ public interface TaskShortcutFactory { } SystemShortcut modalStateSystemShortcut = - taskContainer.getThumbnailView().getTaskOverlay() - .getModalStateSystemShortcut( - taskContainer.getItemInfo(), taskContainer.getTaskView()); + taskContainer.getOverlay().getModalStateSystemShortcut( + taskContainer.getItemInfo(), taskContainer.getTaskView()); return createSingletonShortcutList(modalStateSystemShortcut); } }; diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index 40ea70fd1d..8243ededd2 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -118,8 +118,8 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) { val drawable = getDrawable(container.iconView, splitSelectSource) return SplitAnimInitProps( - container.thumbnailView, - container.thumbnailView.thumbnail, + container.thumbnailViewDeprecated, + container.thumbnailViewDeprecated.thumbnail, drawable!!, fadeWithThumbnail = true, isStagedTask = true, @@ -137,8 +137,8 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC taskView.taskContainers.first().let { val drawable = getDrawable(it.iconView, splitSelectSource) return SplitAnimInitProps( - it.thumbnailView, - it.thumbnailView.thumbnail, + it.thumbnailViewDeprecated, + it.thumbnailViewDeprecated.thumbnail, drawable!!, fadeWithThumbnail = true, isStagedTask = true, @@ -182,7 +182,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC taskViewHeight: Int, isPrimaryTaskSplitting: Boolean ) { - val thumbnail = taskIdAttributeContainer.thumbnailView + val thumbnail = taskIdAttributeContainer.thumbnailViewDeprecated val iconView: View = taskIdAttributeContainer.iconView.asView() builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailViewDeprecated.SPLASH_ALPHA, 1f)) thumbnail.setShowSplashForSplitSelection(true) diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt index 3935c6707d..936f6a1c0a 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt @@ -28,24 +28,20 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.updateLayoutParams import com.android.launcher3.R -import com.android.launcher3.util.CancellableTask import com.android.launcher3.util.RunnableList import com.android.launcher3.util.SplitConfigurationOptions +import com.android.launcher3.util.TransformingTouchDelegate import com.android.launcher3.util.ViewPool import com.android.launcher3.util.rects.set import com.android.quickstep.BaseContainerInterface -import com.android.quickstep.RecentsModel import com.android.quickstep.TaskOverlayFactory import com.android.quickstep.util.RecentsOrientedState import com.android.systemui.shared.recents.model.Task -import com.android.systemui.shared.recents.model.ThumbnailData /** TaskView that contains all tasks that are part of the desktop. */ -// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks. class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : TaskView(context, attrs) { - private val pendingThumbnailRequests = mutableListOf>() private val snapshotDrawParams = object : FullscreenDrawParams(context) { // DesktopTaskView thumbnail's corner radius is independent of fullscreenProgress. @@ -57,31 +53,39 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu context, this, R.layout.task_thumbnail, - 10, - 0 // As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool. + VIEW_POOL_MAX_SIZE, + VIEW_POOL_INITIAL_SIZE ) private val tempPointF = PointF() private val tempRect = Rect() private lateinit var backgroundView: View + private lateinit var iconView: TaskViewIcon private var childCountAtInflation = 0 override fun onFinishInflate() { super.onFinishInflate() - - backgroundView = findViewById(R.id.background)!! - val topMarginPx = container.deviceProfile.overviewTaskThumbnailTopMarginPx - backgroundView.updateLayoutParams { topMargin = topMarginPx } - - val outerRadii = FloatArray(8) { taskCornerRadius } - backgroundView.background = - ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply { - setTint(resources.getColor(android.R.color.system_neutral2_300, context.theme)) + backgroundView = + findViewById(R.id.background)!!.apply { + updateLayoutParams { + topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx + } + background = + ShapeDrawable(RoundRectShape(FloatArray(8) { taskCornerRadius }, null, null)) + .apply { + setTint( + resources.getColor( + android.R.color.system_neutral2_300, + context.theme + ) + ) + } + } + iconView = + getOrInflateIconView(R.id.icon).apply { + val iconBackground = resources.getDrawable(R.drawable.bg_circle, context.theme) + val icon = resources.getDrawable(R.drawable.ic_desktop, context.theme) + setIcon(this, LayerDrawable(arrayOf(iconBackground, icon))) } - - val iconBackground = resources.getDrawable(R.drawable.bg_circle, context.theme) - val icon = resources.getDrawable(R.drawable.ic_desktop, context.theme) - setIcon(iconView, LayerDrawable(arrayOf(iconBackground, icon))) - childCountAtInflation = childCount } @@ -124,7 +128,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } val thumbWidth = (taskSize.width() * scaleWidth).toInt() val thumbHeight = (taskSize.height() * scaleHeight).toInt() - it.thumbnailView.measure( + it.thumbnailViewDeprecated.measure( MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY) ) @@ -135,8 +139,8 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu var taskY = (positionInParent.y * scaleHeight).toInt() // move task down by margin size taskY += thumbnailTopMarginPx - it.thumbnailView.x = taskX.toFloat() - it.thumbnailView.y = taskY.toFloat() + it.thumbnailViewDeprecated.x = taskX.toFloat() + it.thumbnailViewDeprecated.y = taskY.toFloat() if (DEBUG) { Log.d( TAG, @@ -148,23 +152,10 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } override fun onRecycle() { - resetPersistentViewTransforms() - // Clear any references to the thumbnail (it will be re-read either from the cache or the - // system on next bind) - taskContainers.forEach { it.thumbnailView.setThumbnail(it.task, null) } - setOverlayEnabled(false) - onTaskListVisibilityChanged(false) + super.onRecycle() visibility = VISIBLE } - override fun bind( - task: Task, - orientedState: RecentsOrientedState, - taskOverlayFactory: TaskOverlayFactory - ) { - bind(listOf(task), orientedState, taskOverlayFactory) - } - /** Updates this desktop task to the gives task list defined in `tasks` */ fun bind( tasks: List, @@ -185,12 +176,12 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu val taskContainers = taskContainers as ArrayList taskContainers.ensureCapacity(tasks.size) tasks.forEachIndexed { index, task -> - val thumbnailView: TaskThumbnailViewDeprecated + val thumbnailViewDeprecated: TaskThumbnailViewDeprecated if (index >= taskContainers.size) { - thumbnailView = taskThumbnailViewPool.view + thumbnailViewDeprecated = taskThumbnailViewPool.view // Add thumbnailView from to position after the initial child views. addView( - thumbnailView, + thumbnailViewDeprecated, childCountAtInflation, LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, @@ -198,17 +189,22 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu ) ) } else { - thumbnailView = taskContainers[index].thumbnailView + thumbnailViewDeprecated = taskContainers[index].thumbnailViewDeprecated } - thumbnailView.bind(task, taskOverlayFactory) val taskContainer = TaskContainer( - task, - thumbnailView, - iconView, - SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, - null - ) + task, + // TODO(b/338360089): Support new TTV for DesktopTaskView + thumbnailView = null, + thumbnailViewDeprecated, + iconView, + TransformingTouchDelegate(iconView.asView()), + SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, + digitalWellBeingToast = null, + showWindowsView = null, + taskOverlayFactory + ) + .apply { thumbnailViewDeprecated.bind(task, overlay) } if (index >= taskContainers.size) { taskContainers.add(taskContainer) } else { @@ -216,42 +212,20 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } } repeat(taskContainers.size - tasks.size) { - taskContainers.removeLast().apply { - removeView(thumbnailView) - taskThumbnailViewPool.recycle(thumbnailView) + with(taskContainers.removeLast()) { + removeView(thumbnailViewDeprecated) + taskThumbnailViewPool.recycle(thumbnailViewDeprecated) } } setOrientationState(orientedState) } + override fun needsUpdate(dataChange: Int, flag: Int) = + if (flag == FLAG_UPDATE_THUMBNAIL) super.needsUpdate(dataChange, flag) else false + // thumbnailView is laid out differently and is handled in onMeasure - override fun setThumbnailOrientation(orientationState: RecentsOrientedState) {} - - override fun onTaskListVisibilityChanged(visible: Boolean, changes: Int) { - cancelPendingLoadTasks() - if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) { - taskContainers.forEach { - if (visible) { - RecentsModel.INSTANCE.get(context) - .thumbnailCache - .updateThumbnailInBackground(it.task) { thumbnailData: ThumbnailData -> - it.thumbnailView.setThumbnail(it.task, thumbnailData) - } - ?.apply { pendingThumbnailRequests.add(this) } - } else { - it.thumbnailView.setThumbnail(null, null) - // Reset the task thumbnail ref - it.task.thumbnail = null - } - } - } - } - - override fun cancelPendingLoadTasks() { - pendingThumbnailRequests.forEach { it.cancel() } - pendingThumbnailRequests.clear() - } + override fun updateThumbnailSize() {} override fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean) { if (relativeToDragLayer) { @@ -279,59 +253,30 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu callback(true) } - override fun refreshThumbnails(thumbnailDatas: HashMap?) { - // Sets new thumbnails based on the incoming data and refreshes the rest. - thumbnailDatas?.let { - taskContainers.forEach { - val thumbnailData = thumbnailDatas[it.task.key.id] - if (thumbnailData != null) { - it.thumbnailView.setThumbnail(it.task, thumbnailData) - } else { - // Refresh the rest that were not updated. - it.thumbnailView.refresh() - } - } - } - } - // Desktop tile can't be in split screen override fun confirmSecondSplitSelectApp(): Boolean = false - override fun setColorTint(amount: Float, tintColor: Int) { - taskContainers.forEach { it.thumbnailView.dimAlpha = amount } - } - - override fun setThumbnailVisibility(visibility: Int, taskId: Int) { - taskContainers.forEach { it.thumbnailView.visibility = visibility } - } - // TODO(b/330685808) support overlay for Screenshot action override fun setOverlayEnabled(overlayEnabled: Boolean) {} override fun onFullscreenProgressChanged(fullscreenProgress: Float) { - // TODO(b/249371338): this copies parent implementation and makes it work for N thumbs - iconView.setVisibility(if (fullscreenProgress < 1) VISIBLE else INVISIBLE) // Don't show background while we are transitioning to/from fullscreen backgroundView.visibility = if (fullscreenProgress > 0) INVISIBLE else VISIBLE - taskContainers.forEach { - it.thumbnailView.taskOverlay.setFullscreenProgress(fullscreenProgress) - } - setIconsAndBannersFullscreenProgress(fullscreenProgress) - updateSnapshotRadius() } - override fun updateSnapshotRadius() { + override fun updateCurrentFullscreenParams() { + super.updateCurrentFullscreenParams() updateFullscreenParams(snapshotDrawParams) - taskContainers.forEach { it.thumbnailView.setFullscreenParams(snapshotDrawParams) } } - override fun applyThumbnailSplashAlpha() { - taskContainers.forEach { it.thumbnailView.setSplashAlpha(taskThumbnailSplashAlpha) } - } + override fun getThumbnailFullscreenParams() = snapshotDrawParams companion object { private const val TAG = "DesktopTaskView" private const val DEBUG = false + private const val VIEW_POOL_MAX_SIZE = 10 + // As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool. + private const val VIEW_POOL_INITIAL_SIZE = 0 private val ORIGIN = Point(0, 0) } } diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java index 4df9414832..a8ebe51b8a 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -320,7 +320,7 @@ public final class DigitalWellBeingToast { (FrameLayout.LayoutParams) mBanner.getLayoutParams(); DeviceProfile deviceProfile = mContainer.getDeviceProfile(); layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams) - mTaskView.getFirstThumbnailView().getLayoutParams()).bottomMargin; + mTaskView.getFirstThumbnailViewDeprecated().getLayoutParams()).bottomMargin; RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler(); Pair translations = orientationHandler .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(), diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt index f6ae0383a3..efbfa09420 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt @@ -18,31 +18,24 @@ package com.android.quickstep.views import android.app.ActivityTaskManager.INVALID_TASK_ID import android.content.Context import android.graphics.PointF -import android.graphics.Rect import android.util.AttributeSet import android.util.Log -import android.view.MotionEvent import android.view.View -import android.view.ViewStub import com.android.internal.jank.Cuj import com.android.launcher3.Flags.enableOverviewIconMenu import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.launcher3.config.FeatureFlags -import com.android.launcher3.util.CancellableTask import com.android.launcher3.util.RunnableList import com.android.launcher3.util.SplitConfigurationOptions import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED -import com.android.launcher3.util.TransformingTouchDelegate -import com.android.quickstep.RecentsModel import com.android.quickstep.TaskOverlayFactory import com.android.quickstep.util.RecentsOrientedState import com.android.quickstep.util.SplitScreenUtils.Companion.convertLauncherSplitBoundsToShell import com.android.quickstep.util.SplitSelectStateController import com.android.systemui.shared.recents.model.Task -import com.android.systemui.shared.recents.model.ThumbnailData import com.android.systemui.shared.recents.utilities.PreviewPositionHelper import com.android.systemui.shared.system.InteractionJankMonitorWrapper import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition @@ -60,42 +53,14 @@ import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosi class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : TaskView(context, attrs) { // TODO(b/336612373): Support new TTV for GroupedTaskView - private val icon2CenterCoordinates = FloatArray(2) - private val digitalWellBeingToast2: DigitalWellBeingToast = - DigitalWellBeingToast(container, this) - - private lateinit var snapshotView2: TaskThumbnailViewDeprecated - private lateinit var iconView2: TaskViewIcon - private lateinit var icon2TouchDelegate: TransformingTouchDelegate - var splitBoundsConfig: SplitConfigurationOptions.SplitBounds? = null private set - private var thumbnailLoadRequest2: CancellableTask? = null - private var iconLoadRequest2: CancellableTask<*>? = null @get:PersistentSnapPosition val snapPosition: Int /** Returns the [PersistentSnapPosition] of this pair of tasks. */ get() = splitBoundsConfig?.snapPosition ?: STAGE_POSITION_UNDEFINED - @get:Deprecated("Use {@link #mTaskContainers} instead.") - private val secondTask: Task - /** Returns the second task bound to this TaskView. */ - get() = taskContainers[1].task - - override fun onFinishInflate() { - super.onFinishInflate() - snapshotView2 = findViewById(R.id.bottomright_snapshot)!! - val iconViewStub2 = - findViewById(R.id.bottomRight_icon)!!.apply { - layoutResource = - if (enableOverviewIconMenu()) R.layout.icon_app_chip_view - else R.layout.icon_view - } - iconView2 = iconViewStub2.inflate() as TaskViewIcon - icon2TouchDelegate = TransformingTouchDelegate(iconView2.asView()) - } - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val widthSize = MeasureSpec.getSize(widthMeasureSpec) @@ -105,8 +70,8 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu val initSplitTaskId = getThisTaskCurrentlyInSplitSelection() if (initSplitTaskId == INVALID_TASK_ID) { pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds( - taskThumbnailViewDeprecated, - snapshotView2, + taskContainers[0].thumbnailViewDeprecated, + taskContainers[1].thumbnailViewDeprecated, widthSize, heightSize, splitBoundsConfig, @@ -117,20 +82,24 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu // 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 - taskThumbnailViewDeprecated.applySplitSelectTranslateX( - taskThumbnailViewDeprecated.translationX - ) - taskThumbnailViewDeprecated.applySplitSelectTranslateY( - taskThumbnailViewDeprecated.translationY - ) - snapshotView2.applySplitSelectTranslateX(snapshotView2.translationX) - snapshotView2.applySplitSelectTranslateY(snapshotView2.translationY) + taskContainers[0] + .thumbnailViewDeprecated + .applySplitSelectTranslateX(taskContainers[0].thumbnailViewDeprecated.translationX) + taskContainers[0] + .thumbnailViewDeprecated + .applySplitSelectTranslateY(taskContainers[0].thumbnailViewDeprecated.translationY) + taskContainers[1] + .thumbnailViewDeprecated + .applySplitSelectTranslateX(taskContainers[1].thumbnailViewDeprecated.translationX) + taskContainers[1] + .thumbnailViewDeprecated + .applySplitSelectTranslateY(taskContainers[1].thumbnailViewDeprecated.translationY) } else { // Currently being split with this taskView, let the non-split selected thumbnail // take up full thumbnail area taskContainers .firstOrNull { it.task.key.id != initSplitTaskId } - ?.thumbnailView + ?.thumbnailViewDeprecated ?.measure( widthMeasureSpec, MeasureSpec.makeMeasureSpec( @@ -146,7 +115,6 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu override fun onRecycle() { super.onRecycle() - snapshotView2.setThumbnail(secondTask, null) splitBoundsConfig = null } @@ -158,30 +126,42 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu splitBoundsConfig: SplitConfigurationOptions.SplitBounds?, ) { cancelPendingLoadTasks() - setupTaskContainers(primaryTask, taskOverlayFactory) taskContainers = listOf( - taskContainers[0].apply { stagePosition = STAGE_POSITION_TOP_OR_LEFT }, - TaskContainer( + createTaskContainer( + primaryTask, + R.id.snapshot, + R.id.icon, + R.id.show_windows, + STAGE_POSITION_TOP_OR_LEFT, + taskOverlayFactory + ), + createTaskContainer( secondaryTask, - findViewById(R.id.bottomright_snapshot)!!, - iconView2, + R.id.bottomright_snapshot, + R.id.bottomRight_icon, + R.id.show_windows_right, STAGE_POSITION_BOTTOM_OR_RIGHT, - digitalWellBeingToast2 + taskOverlayFactory ) ) - snapshotView2.bind(secondaryTask, taskOverlayFactory) - this.splitBoundsConfig = splitBoundsConfig - this.splitBoundsConfig?.let { - taskThumbnailViewDeprecated.previewPositionHelper.setSplitBounds( - convertLauncherSplitBoundsToShell(it), - PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT - ) - snapshotView2.previewPositionHelper.setSplitBounds( - convertLauncherSplitBoundsToShell(it), - PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT - ) - } + this.splitBoundsConfig = + splitBoundsConfig?.also { + taskContainers[0] + .thumbnailViewDeprecated + .previewPositionHelper + .setSplitBounds( + convertLauncherSplitBoundsToShell(it), + PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT + ) + taskContainers[1] + .thumbnailViewDeprecated + .previewPositionHelper + .setSplitBounds( + convertLauncherSplitBoundsToShell(it), + PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT + ) + } setOrientationState(orientedState) } @@ -206,24 +186,18 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu val iconMargins = (iconViewMarginStart + iconViewBackgroundMarginStart) * 2 // setMaxWidth() needs to be called before mIconView.setIconOrientation which is // called in the super below. - (iconView as IconAppChipView).setMaxWidth( + (taskContainers[0].iconView as IconAppChipView).setMaxWidth( groupedTaskViewSizes.first.x - iconMargins ) - (iconView2 as IconAppChipView).setMaxWidth( + (taskContainers[1].iconView as IconAppChipView).setMaxWidth( groupedTaskViewSizes.second.x - iconMargins ) } } super.setOrientationState(orientationState) - iconView2.setIconOrientation(orientationState, isGridTask) updateIconPlacement() } - override fun setThumbnailOrientation(orientationState: RecentsOrientedState) { - super.setThumbnailOrientation(orientationState) - digitalWellBeingToast2.initialize(secondTask) - } - private fun updateIconPlacement() { val splitBoundsConfig = splitBoundsConfig ?: return val taskIconHeight = container.deviceProfile.overviewTaskIconSizePx @@ -237,8 +211,8 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu layoutParams.height ) pagedOrientationHandler.setSplitIconParams( - iconView.asView(), - iconView2.asView(), + taskContainers[0].iconView.asView(), + taskContainers[1].iconView.asView(), taskIconHeight, groupedTaskViewSizes.first.x, groupedTaskViewSizes.first.y, @@ -250,11 +224,11 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu ) } else { pagedOrientationHandler.setSplitIconParams( - iconView.asView(), - iconView2.asView(), + taskContainers[0].iconView.asView(), + taskContainers[1].iconView.asView(), taskIconHeight, - taskThumbnailViewDeprecated.measuredWidth, - taskThumbnailViewDeprecated.measuredHeight, + taskContainers[0].thumbnailViewDeprecated.measuredWidth, + taskContainers[0].thumbnailViewDeprecated.measuredHeight, measuredHeight, measuredWidth, isRtl, @@ -264,104 +238,11 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } } - override fun onTaskListVisibilityChanged(visible: Boolean, changes: Int) { - super.onTaskListVisibilityChanged(visible, changes) - val model = RecentsModel.INSTANCE.get(context) - if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) { - if (visible) { - thumbnailLoadRequest2 = - model.thumbnailCache.updateThumbnailInBackground(secondTask) { - snapshotView2.setThumbnail(secondTask, it) - } - } else { - snapshotView2.setThumbnail(null, null) - // Reset the task thumbnail reference as well (it will be fetched from the cache or - // reloaded next time we need it) - secondTask.thumbnail = null - } - } - if (needsUpdate(changes, FLAG_UPDATE_ICON)) { - if (visible) { - iconLoadRequest2 = - model.iconCache.updateIconInBackground(secondTask) { - setIcon(iconView2, it.icon) - if (enableOverviewIconMenu()) { - setText(iconView2, it.title) - } - digitalWellBeingToast2.initialize(secondTask) - digitalWellBeingToast2.setSplitConfiguration(splitBoundsConfig) - digitalWellBeingToast.setSplitConfiguration(splitBoundsConfig) - } - } else { - setIcon(iconView2, null) - if (enableOverviewIconMenu()) { - setText(iconView2, null) - } - } - } - } - - override fun cancelPendingLoadTasks() { - super.cancelPendingLoadTasks() - thumbnailLoadRequest2?.cancel() - thumbnailLoadRequest2 = null - iconLoadRequest2?.cancel() - iconLoadRequest2 = null - } - - override fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean) { - splitBoundsConfig ?: return super.getThumbnailBounds(bounds, relativeToDragLayer) - if (relativeToDragLayer) { - val firstThumbnailBounds = Rect() - val secondThumbnailBounds = Rect() - with(container.dragLayer) { - getDescendantRectRelativeToSelf(snapshotView, firstThumbnailBounds) - getDescendantRectRelativeToSelf(snapshotView2, secondThumbnailBounds) - } - bounds.set(firstThumbnailBounds) - bounds.union(secondThumbnailBounds) - } else { - bounds.set(getSnapshotViewBounds(snapshotView)) - bounds.union(getSnapshotViewBounds(snapshotView2)) - } - } - - private fun getSnapshotViewBounds(snapshotView: View): Rect { - val snapshotViewX = Math.round(snapshotView.x) - val snapshotViewY = Math.round(snapshotView.y) - return Rect( - snapshotViewX, - snapshotViewY, - snapshotViewX + snapshotView.width, - snapshotViewY + snapshotView.height - ) - } - - /** - * Sets up an on-click listener and the visibility for show_windows icon on top of each task. - */ - override fun setUpShowAllInstancesListener() { - // sets up the listener for the left/top task - super.setUpShowAllInstancesListener() - // right/bottom task's base package name - val taskPackageName = taskContainers[1].task.key.packageName - // icon of the right/bottom task - val showWindowsView = findViewById(R.id.show_windows_right)!! - updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName)) - } - fun updateSplitBoundsConfig(splitBounds: SplitConfigurationOptions.SplitBounds?) { splitBoundsConfig = splitBounds invalidate() } - override fun offerTouchToChildren(event: MotionEvent): Boolean { - computeAndSetIconTouchDelegate(iconView2, icon2CenterCoordinates, icon2TouchDelegate) - return if (icon2TouchDelegate.onTouchEvent(event)) { - true - } else super.offerTouchToChildren(event) - } - override fun launchTaskAnimated(): RunnableList? { if (taskContainers.isEmpty()) { Log.d(TAG, "launchTaskAnimated - task is not bound") @@ -414,12 +295,6 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } } - override fun refreshThumbnails(thumbnailDatas: HashMap?) { - super.refreshThumbnails(thumbnailDatas) - thumbnailDatas?.get(secondTask.key.id)?.let { snapshotView2.setThumbnail(secondTask, it) } - ?: { snapshotView2.refresh() } - } - /** * Returns taskId that split selection was initiated with, [INVALID_TASK_ID] if no tasks in this * TaskView are part of split selection @@ -437,14 +312,14 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu // checks below aren't reliable since both of those views may be gone/transformed val initSplitTaskId = getThisTaskCurrentlyInSplitSelection() if (initSplitTaskId != INVALID_TASK_ID) { - return if (initSplitTaskId == firstTask.key.id) 1 else 0 + return if (initSplitTaskId == taskContainers[0].task.key.id) 1 else 0 } } // Check which of the two apps was selected if ( - iconView2.asView().containsPoint(mLastTouchDownPosition) || - snapshotView2.containsPoint(mLastTouchDownPosition) + taskContainers[1].iconView.asView().containsPoint(lastTouchDownPosition) || + taskContainers[1].thumbnailViewDeprecated.containsPoint(lastTouchDownPosition) ) { return 1 } @@ -457,36 +332,6 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu return Utilities.pointInView(this, localPos[0], localPos[1], 0f /* slop */) } - override fun setIconsAndBannersTransitionProgress(progress: Float, invert: Boolean) { - super.setIconsAndBannersTransitionProgress(progress, invert) - getIconContentScale(invert).let { - iconView2.setContentAlpha(it) - digitalWellBeingToast2.updateBannerOffset(1f - it) - } - } - - override fun setColorTint(amount: Float, tintColor: Int) { - super.setColorTint(amount, tintColor) - iconView2.setIconColorTint(tintColor, amount) - snapshotView2.dimAlpha = amount - digitalWellBeingToast2.setBannerColorTint(tintColor, amount) - } - - /** - * Sets visibility for thumbnails and associated elements (DWB banners). IconView is unaffected. - * - * When setting INVISIBLE, sets the visibility for the last selected child task. When setting - * VISIBLE (as a reset), sets the visibility for both tasks. - */ - override fun setThumbnailVisibility(visibility: Int, taskId: Int) { - taskContainers.forEach { - if (visibility == VISIBLE || it.task.key.id == taskId) { - it.thumbnailView.visibility = visibility - it.digitalWellBeingToast?.setBannerVisibility(visibility) - } - } - } - override fun setOverlayEnabled(overlayEnabled: Boolean) { if (FeatureFlags.enableAppPairs()) { super.setOverlayEnabled(overlayEnabled) @@ -495,26 +340,6 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } } - override fun refreshTaskThumbnailSplash() { - super.refreshTaskThumbnailSplash() - snapshotView2.refreshSplashView() - } - - override fun updateSnapshotRadius() { - super.updateSnapshotRadius() - snapshotView2.setFullscreenParams(currentFullscreenParams) - } - - override fun applyThumbnailSplashAlpha() { - super.applyThumbnailSplashAlpha() - snapshotView2.setSplashAlpha(taskThumbnailSplashAlpha) - } - - override fun resetViewTransforms() { - super.resetViewTransforms() - snapshotView2.resetViewTransforms() - } - companion object { private const val TAG = "GroupedTaskView" } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 3c0445f322..4e5d646e27 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1006,7 +1006,8 @@ public abstract class RecentsView container.getIconView().getDrawable() != null)) { tv.onTaskListVisibilityChanged(true /* visible */); } } @@ -1058,7 +1059,7 @@ public abstract class RecentsView taskContainer.getOverlay().resetModalVisuals()); } } @@ -4761,8 +4763,8 @@ public abstract class RecentsView { @@ -5279,7 +5281,7 @@ public abstract class RecentsView mOverlay; private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mSplashBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -190,9 +187,9 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab /** * Updates the thumbnail to draw the provided task */ - public void bind(Task task, TaskOverlayFactory taskOverlayFactory) { - mTaskOverlayFactory = taskOverlayFactory; - getTaskOverlay().reset(); + public void bind(Task task, TaskOverlay overlay) { + mOverlay = overlay; + mOverlay.reset(); mTask = task; int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000; mPaint.setColor(color); @@ -202,14 +199,14 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab } /** - * Sets TaskOverlayFactory without binding a task. + * Sets TaskOverlay without binding a task. * * @deprecated Should only be used when using new * {@link com.android.quickstep.task.thumbnail.TaskThumbnailView}. */ @Deprecated - public void setTaskOverlayFactory(TaskOverlayFactory taskOverlayFactory) { - mTaskOverlayFactory = taskOverlayFactory; + public void setTaskOverlay(TaskOverlay overlay) { + mOverlay = overlay; } /** @@ -265,7 +262,7 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab mBitmapShader = null; mThumbnailData = null; mPaint.setShader(null); - getTaskOverlay().reset(); + mOverlay.reset(); } updateThumbnailPaintFilter(); } @@ -293,13 +290,6 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab invalidate(); } - public TaskOverlay getTaskOverlay() { - if (mOverlay == null) { - mOverlay = mTaskOverlayFactory.createOverlay(this); - } - return mOverlay; - } - public float getDimAlpha() { return mDimAlpha; } @@ -374,7 +364,6 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) { mFullscreenParams = fullscreenParams; - getTaskOverlay().setFullscreenParams(fullscreenParams); invalidate(); } @@ -551,10 +540,10 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab */ private void refreshOverlay() { if (mOverlayEnabled) { - getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.getMatrix(), + mOverlay.initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.getMatrix(), mPreviewPositionHelper.isOrientationChanged()); } else { - getTaskOverlay().reset(); + mOverlay.reset(); } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index baeaa87ea0..1490fd03bb 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -42,7 +42,6 @@ import android.widget.FrameLayout import android.widget.Toast import androidx.annotation.IntDef import androidx.annotation.VisibleForTesting -import androidx.core.view.children import androidx.core.view.updateLayoutParams import com.android.app.animation.Interpolators import com.android.launcher3.Flags.enableCursorHoverStates @@ -57,6 +56,7 @@ import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH import com.android.launcher3.logging.StatsLogManager.LauncherEvent +import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.model.data.ItemInfoWithIcon import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.pm.UserCache @@ -79,6 +79,7 @@ import com.android.quickstep.RecentsModel import com.android.quickstep.RemoteAnimationTargets import com.android.quickstep.TaskAnimationManager import com.android.quickstep.TaskOverlayFactory +import com.android.quickstep.TaskOverlayFactory.TaskOverlay import com.android.quickstep.TaskUtils import com.android.quickstep.TaskViewUtils import com.android.quickstep.orientation.RecentsPagedOrientationHandler @@ -132,7 +133,7 @@ constructor( /** Returns a copy of integer array containing taskIds of all tasks in the TaskView. */ get() = taskContainers.map { it.task.key.id }.toIntArray() val thumbnailViews: Array - get() = taskContainers.map { it.thumbnailView }.toTypedArray() + get() = taskContainers.map { it.thumbnailViewDeprecated }.toTypedArray() val isGridTask: Boolean /** Returns whether the task is part of overview grid and not being focused. */ get() = container.deviceProfile.isTablet && !isFocusedTask @@ -147,27 +148,22 @@ constructor( val pagedOrientationHandler: RecentsPagedOrientationHandler get() = orientedState.orientationHandler - @get:Deprecated("Use {@link #mTaskContainers} instead.") + @get:Deprecated("Use [taskContainers] instead.") val firstTask: Task /** Returns the first task bound to this TaskView. */ get() = taskContainers[0].task - @get:Deprecated("Use {@link #mTaskContainers} instead.") - val firstThumbnailView: TaskThumbnailViewDeprecated + @get:Deprecated("Use [taskContainers] instead.") + val firstThumbnailViewDeprecated: TaskThumbnailViewDeprecated /** Returns the first thumbnailView of the TaskView. */ - get() = taskContainers[0].thumbnailView - @get:Deprecated("Use {@link #mTaskContainers} instead.") - val firstIconView: TaskViewIcon - /** Returns the first iconView of the TaskView. */ - get() = taskContainers[0].iconView - protected val currentFullscreenParams = FullscreenDrawParams(context) + get() = taskContainers[0].thumbnailViewDeprecated + @get:Deprecated("Use [taskContainers] instead.") + val firstItemInfo: ItemInfo + get() = taskContainers[0].itemInfo + + private val currentFullscreenParams = FullscreenDrawParams(context) protected val container: RecentsViewContainer = RecentsViewContainer.containerFromContext(context) - @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) - val digitalWellBeingToast = DigitalWellBeingToast(container, this) - protected val mLastTouchDownPosition = PointF() - protected val snapshotView: View - get() = - if (enableRefactorTaskThumbnail()) taskThumbnailView!! else taskThumbnailViewDeprecated + protected val lastTouchDownPosition = PointF() // Derived view properties protected val persistentScale: Float @@ -228,9 +224,9 @@ constructor( TASK_RESISTANCE_TRANSLATION_Y ) - private val mIconCenterCoordinates = FloatArray(2) - private val mFocusBorderAnimator: BorderAnimator? - private val mHoverBorderAnimator: BorderAnimator? + private val tempCoordinates = FloatArray(2) + private val focusBorderAnimator: BorderAnimator? + private val hoverBorderAnimator: BorderAnimator? private val rootViewDisplayId: Int get() = rootView.display?.displayId ?: Display.DEFAULT_DISPLAY @@ -238,16 +234,6 @@ constructor( lateinit var taskContainers: List protected set lateinit var orientedState: RecentsOrientedState - protected lateinit var taskThumbnailViewDeprecated: TaskThumbnailViewDeprecated - protected lateinit var iconView: TaskViewIcon - /** - * This technically can be a vanilla [android.view.TouchDelegate] class, however that class - * requires setting the touch bounds at construction, so we'd repeatedly be created many - * instances unnecessarily as scrolling occurs, whereas [TransformingTouchDelegate] allows touch - * delegated bounds only to be updated. - */ - private lateinit var iconTouchDelegate: TransformingTouchDelegate - private var taskThumbnailView: TaskThumbnailView? = null var taskViewId = -1 var isEndQuickSwitchCuj = false @@ -382,26 +368,26 @@ constructor( field = value // Set the animation correctly in case it misses the hover/focus event during state // transition - mHoverBorderAnimator?.setBorderVisibility(visible = field && isHovered, animated = true) - mFocusBorderAnimator?.setBorderVisibility(visible = field && isFocused, animated = true) + hoverBorderAnimator?.setBorderVisibility(visible = field && isHovered, animated = true) + focusBorderAnimator?.setBorderVisibility(visible = field && isFocused, animated = true) } protected var iconScaleAnimStartProgress = 0f private var focusTransitionProgress = 1f private var iconAndDimAnimator: ObjectAnimator? = null // The current background requests to load the task thumbnail and icon - private var thumbnailLoadRequest: CancellableTask<*>? = null - private var iconLoadRequest: CancellableTask<*>? = null + private val pendingThumbnailLoadRequests = mutableListOf>() + private val pendingIconLoadRequests = mutableListOf>() private var isClickableAsLiveTile = true init { - setOnClickListener { view: View -> onClick(view) } + setOnClickListener { _ -> onClick() } val keyboardFocusHighlightEnabled = (ENABLE_KEYBOARD_QUICK_SWITCH.get() || enableFocusOutline()) val cursorHoverStatesEnabled = enableCursorHoverStates() setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled) context.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes).use { - mFocusBorderAnimator = + this.focusBorderAnimator = focusBorderAnimator ?: if (keyboardFocusHighlightEnabled) createSimpleBorderAnimator( @@ -417,7 +403,7 @@ constructor( ) ) else null - mHoverBorderAnimator = + this.hoverBorderAnimator = hoverBorderAnimator ?: if (cursorHoverStatesEnabled) createSimpleBorderAnimator( @@ -436,28 +422,6 @@ constructor( } } - override fun onFinishInflate() { - super.onFinishInflate() - taskThumbnailViewDeprecated = findViewById(R.id.snapshot)!! - if (enableRefactorTaskThumbnail()) { - val indexOfSnapshotView = indexOfChild(taskThumbnailViewDeprecated) - taskThumbnailView = - TaskThumbnailView(mContext).apply { - layoutParams = taskThumbnailViewDeprecated.layoutParams - addView(this, indexOfSnapshotView) - } - taskThumbnailViewDeprecated.visibility = GONE - } - val iconViewStub = - findViewById(R.id.icon)!!.apply { - layoutResource = - if (enableOverviewIconMenu()) R.layout.icon_app_chip_view - else R.layout.icon_view - } - iconView = iconViewStub.inflate() as TaskViewIcon - iconTouchDelegate = TransformingTouchDelegate(iconView.asView()) - } - @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) public override fun onFocusChanged( gainFocus: Boolean, @@ -466,7 +430,7 @@ constructor( ) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect) if (borderEnabled) { - mFocusBorderAnimator?.setBorderVisibility(gainFocus, /* animated= */ true) + focusBorderAnimator?.setBorderVisibility(gainFocus, /* animated= */ true) } } @@ -474,9 +438,9 @@ constructor( if (borderEnabled) { when (event.action) { MotionEvent.ACTION_HOVER_ENTER -> - mHoverBorderAnimator?.setBorderVisibility(visible = true, animated = true) + hoverBorderAnimator?.setBorderVisibility(visible = true, animated = true) MotionEvent.ACTION_HOVER_EXIT -> - mHoverBorderAnimator?.setBorderVisibility(visible = false, animated = true) + hoverBorderAnimator?.setBorderVisibility(visible = false, animated = true) else -> {} } } @@ -491,16 +455,15 @@ constructor( override fun dispatchTouchEvent(ev: MotionEvent): Boolean { val recentsView = recentsView ?: return false val splitSelectStateController = recentsView.splitSelectController - // Disable taps for split selection animation unless we have multiple tasks + // Disable taps for split selection animation unless we have a task not being selected if ( splitSelectStateController.isSplitSelectActive && - splitSelectStateController.initialTaskId == firstTask.key.id && - !containsMultipleTasks() + taskContainers.none { it.task.key.id != splitSelectStateController.initialTaskId } ) { return false } if (ev.action == MotionEvent.ACTION_DOWN) { - mLastTouchDownPosition.apply { + with(lastTouchDownPosition) { x = ev.x y = ev.y } @@ -510,8 +473,8 @@ constructor( override fun draw(canvas: Canvas) { // Draw border first so any child views outside of the thumbnail bounds are drawn above it. - mFocusBorderAnimator?.drawBorder(canvas) - mHoverBorderAnimator?.drawBorder(canvas) + focusBorderAnimator?.drawBorder(canvas) + hoverBorderAnimator?.drawBorder(canvas) super.draw(canvas) } @@ -540,7 +503,7 @@ constructor( if (enableRefactorTaskThumbnail()) { notifyIsRunningTaskUpdated() } else { - taskThumbnailViewDeprecated.setThumbnail(firstTask, null) + taskContainers.forEach { it.thumbnailViewDeprecated.setThumbnail(it.task, null) } } setOverlayEnabled(false) onTaskListVisibilityChanged(false) @@ -566,7 +529,8 @@ constructor( } } } - if (digitalWellBeingToast.hasLimit()) { + // TODO(b/341672022): handle multiple digitalWellBeingToast accessibility actions + if (taskContainers[0].digitalWellBeingToast?.hasLimit() == true) { addAction( AccessibilityNodeInfo.AccessibilityAction( R.string.accessibility_app_usage_settings, @@ -593,7 +557,8 @@ constructor( return true } if (action == R.string.accessibility_app_usage_settings) { - digitalWellBeingToast.openAppUsageSettings(this) + // TODO(b/341672022): handle multiple digitalWellBeingToast accessibility actions + taskContainers[0].digitalWellBeingToast?.openAppUsageSettings(this) return true } taskContainers.forEach { @@ -614,27 +579,73 @@ constructor( taskOverlayFactory: TaskOverlayFactory ) { cancelPendingLoadTasks() - setupTaskContainers(task, taskOverlayFactory) + taskContainers = + listOf( + createTaskContainer( + task, + R.id.snapshot, + R.id.icon, + R.id.show_windows, + STAGE_POSITION_UNDEFINED, + taskOverlayFactory + ) + ) setOrientationState(orientedState) } - protected fun setupTaskContainers(task: Task, taskOverlayFactory: TaskOverlayFactory) { - taskContainers = - listOf( - TaskContainer( - task, - taskThumbnailViewDeprecated, - iconView, - STAGE_POSITION_UNDEFINED, - digitalWellBeingToast - ) - ) + protected fun createTaskContainer( + task: Task, + @IdRes thumbnailViewId: Int, + @IdRes iconViewId: Int, + @IdRes showWindowViewId: Int, + @StagePosition stagePosition: Int, + taskOverlayFactory: TaskOverlayFactory + ): TaskContainer { + val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = findViewById(thumbnailViewId)!! + val thumbnailView: TaskThumbnailView? if (enableRefactorTaskThumbnail()) { - taskThumbnailViewDeprecated.setTaskOverlayFactory(taskOverlayFactory) - bindTaskThumbnailView() + val indexOfSnapshotView = indexOfChild(thumbnailViewDeprecated) + thumbnailView = + TaskThumbnailView(context).apply { + layoutParams = thumbnailViewDeprecated.layoutParams + addView(this, indexOfSnapshotView) + } + thumbnailViewDeprecated.visibility = GONE } else { - taskThumbnailViewDeprecated.bind(task, taskOverlayFactory) + thumbnailView = null } + val iconView = getOrInflateIconView(iconViewId) + return TaskContainer( + task, + thumbnailView, + thumbnailViewDeprecated, + iconView, + TransformingTouchDelegate(iconView.asView()), + stagePosition, + DigitalWellBeingToast(container, this), + findViewById(showWindowViewId)!!, + taskOverlayFactory + ) + .apply { + if (enableRefactorTaskThumbnail()) { + thumbnailViewDeprecated.setTaskOverlay(overlay) + bindThumbnailView() + } else { + thumbnailViewDeprecated.bind(task, overlay) + } + } + } + + protected fun getOrInflateIconView(@IdRes iconViewId: Int): TaskViewIcon { + val iconView = findViewById(iconViewId)!! + return iconView as? TaskViewIcon + ?: (iconView as ViewStub) + .apply { + layoutResource = + if (enableOverviewIconMenu()) R.layout.icon_app_chip_view + else R.layout.icon_view + } + .inflate() as TaskViewIcon } protected fun isTaskContainersInitialized() = this::taskContainers.isInitialized @@ -650,31 +661,17 @@ constructor( /** Check if given `taskId` is tracked in this view */ fun containsTaskId(taskId: Int) = getTaskContainerById(taskId) != null - // 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 - private fun bindTaskThumbnailView() { - taskThumbnailView!!.viewModel.bind(TaskThumbnail(firstTask, isRunningTask)) - } - open fun setOrientationState(orientationState: RecentsOrientedState) { this.orientedState = orientationState - iconView.setIconOrientation(orientationState, isGridTask) + taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) } setThumbnailOrientation(orientationState) } protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) { - val thumbnailTopMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx - - // TODO(b/271468547), we should default to setting translations only on the snapshot instead - // of a hybrid of both margins and translations - snapshotView.updateLayoutParams { topMargin = thumbnailTopMargin } - - // 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()) { - taskThumbnailViewDeprecated.taskOverlay.updateOrientationState(orientationState) + taskContainers.forEach { + it.overlay.updateOrientationState(orientationState) + it.digitalWellBeingToast?.initialize(it.task) } - digitalWellBeingToast.initialize(firstTask) } /** @@ -696,7 +693,6 @@ constructor( if (container.deviceProfile.isTablet) { val boxWidth: Int val boxHeight: Int - val isFocusedTask = isFocusedTask if (isFocusedTask) { // Task will be focused and should use focused task size. Use focusTaskRatio // that is associated with the original orientation of the focused task. @@ -736,19 +732,29 @@ constructor( width = expectedWidth height = expectedHeight } + updateThumbnailSize() + } + + protected open fun updateThumbnailSize() { + // TODO(b/271468547), we should default to setting translations only on the snapshot instead + // of a hybrid of both margins and translations + taskContainers[0].snapshotView.updateLayoutParams { + topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx + } } /** Returns the thumbnail's bounds, optionally relative to the screen. */ @JvmOverloads open fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean = false) { - val snapshotView = snapshotView - if (relativeToDragLayer) { - container.dragLayer.getDescendantRectRelativeToSelf(snapshotView, bounds) - } else { - bounds.apply { - set(snapshotView) - offset(Math.round(snapshotView.translationX), Math.round(snapshotView.translationY)) + bounds.setEmpty() + taskContainers.forEach { + val thumbnailBounds = Rect() + if (relativeToDragLayer) { + container.dragLayer.getDescendantRectRelativeToSelf(it.snapshotView, bounds) + } else { + thumbnailBounds.set(it.snapshotView) } + bounds.union(thumbnailBounds) } } @@ -768,42 +774,45 @@ constructor( */ open fun onTaskListVisibilityChanged(visible: Boolean, @TaskDataChanges changes: Int) { cancelPendingLoadTasks() - val model = RecentsModel.INSTANCE.get(context) + val recentsModel = RecentsModel.INSTANCE.get(context) // These calls are no-ops if the data is already loaded, try and load the high // resolution thumbnail if the state permits if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) { - if (visible) { - thumbnailLoadRequest = - model.thumbnailCache.updateThumbnailInBackground(firstTask) { - if (!enableRefactorTaskThumbnail()) { - // TODO(b/334825222) add thumbnail state - taskThumbnailViewDeprecated.setThumbnail(firstTask, it) - } + if (!enableRefactorTaskThumbnail()) { + // TODO(b/334825222) add thumbnail state + taskContainers.forEach { + if (visible) { + recentsModel.thumbnailCache + .updateThumbnailInBackground(it.task) { thumbnailData -> + it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData) + } + ?.also { request -> pendingThumbnailLoadRequests.add(request) } + } else { + it.thumbnailViewDeprecated.setThumbnail(null, null) + // Reset the task thumbnail reference as well (it will be fetched from the + // cache or reloaded next time we need it) + it.task.thumbnail = null } - } else { - if (!enableRefactorTaskThumbnail()) { - // TODO(b/334825222) add thumbnail state - taskThumbnailViewDeprecated.setThumbnail(null, null) } - // Reset the task thumbnail reference as well (it will be fetched from the cache or - // reloaded next time we need it) - firstTask.thumbnail = null } } if (needsUpdate(changes, FLAG_UPDATE_ICON)) { - if (visible) { - iconLoadRequest = - model.iconCache.updateIconInBackground(firstTask) { - setIcon(iconView, it.icon) - if (enableOverviewIconMenu()) { - setText(iconView, it.title) + taskContainers.forEach { + if (visible) { + recentsModel.iconCache + .updateIconInBackground(it.task) { thumbnailData -> + setIcon(it.iconView, thumbnailData.icon) + if (enableOverviewIconMenu()) { + setText(it.iconView, thumbnailData.title) + } + it.digitalWellBeingToast?.initialize(thumbnailData) } - digitalWellBeingToast.initialize(it) + ?.also { request -> pendingIconLoadRequests.add(request) } + } else { + setIcon(it.iconView, null) + if (enableOverviewIconMenu()) { + setText(it.iconView, null) } - } else { - setIcon(iconView, null) - if (enableOverviewIconMenu()) { - setText(iconView, null) } } } @@ -812,14 +821,14 @@ constructor( } } - protected fun needsUpdate(@TaskDataChanges dataChange: Int, @TaskDataChanges flag: Int) = + protected open fun needsUpdate(@TaskDataChanges dataChange: Int, @TaskDataChanges flag: Int) = (dataChange and flag) == flag protected open fun cancelPendingLoadTasks() { - thumbnailLoadRequest?.cancel() - thumbnailLoadRequest = null - iconLoadRequest?.cancel() - iconLoadRequest = null + pendingThumbnailLoadRequests.forEach { it.cancel() } + pendingThumbnailLoadRequests.clear() + pendingIconLoadRequests.forEach { it.cancel() } + pendingIconLoadRequests.clear() } protected fun setIcon(iconView: TaskViewIcon, icon: Drawable?) { @@ -852,13 +861,18 @@ constructor( // TODO(b/334825222) add thumbnail logic return } - thumbnailDatas?.get(firstTask.key.id)?.let { - taskThumbnailViewDeprecated.setThumbnail(firstTask, it) + + taskContainers.forEach { + val thumbnailData = thumbnailDatas?.get(it.task.key.id) + if (thumbnailData != null) { + it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData) + } else { + it.thumbnailViewDeprecated.refresh() + } } - ?: { taskThumbnailViewDeprecated.refresh() } } - private fun onClick(view: View) { + private fun onClick() { if (confirmSecondSplitSelectApp()) { Log.d("b/310064698", "${taskIds.contentToString()} - onClick - split select is active") return @@ -872,7 +886,7 @@ constructor( Log.d("b/310064698", "${taskIds.contentToString()} - onClick - callbackList: $callbackList") container.statsLogManager .logger() - .withItemInfo(getItemInfo()) + .withItemInfo(firstItemInfo) .log(LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP) } @@ -893,7 +907,7 @@ constructor( } if ( ActivityManagerWrapper.getInstance() - .startActivityFromRecents(firstTask.key, opts.options) + .startActivityFromRecents(taskContainers[0].task.key, opts.options) ) { Log.d( TAG, @@ -937,12 +951,13 @@ constructor( "startActivityFromRecentsAsync", taskIds.contentToString() ) + val firstContainer = taskContainers[0] val failureListener = TaskRemovedDuringLaunchListener(context.applicationContext) if (isQuickSwitch) { // We only listen for failures to launch in quickswitch because the during this // gesture launcher is in the background state, vs other launches which are in // the actual overview state - failureListener.register(container, firstTask.key.id) { + failureListener.register(container, firstContainer.task.key.id) { notifyTaskLaunchFailed() recentsView?.let { // Disable animations for now, as it is an edge case and the app usually @@ -976,12 +991,14 @@ constructor( } // TODO(b/334826842) add splash functionality to new TTV if (!enableRefactorTaskThumbnail()) { - disableStartingWindow = taskThumbnailViewDeprecated.shouldShowSplashView() + disableStartingWindow = + firstContainer.thumbnailViewDeprecated.shouldShowSplashView() } } Executors.UI_HELPER_EXECUTOR.execute { if ( - !ActivityManagerWrapper.getInstance().startActivityFromRecents(firstTask.key, opts) + !ActivityManagerWrapper.getInstance() + .startActivityFromRecents(firstContainer.task.key, opts) ) { // If the call to start activity failed, then post the result immediately, // otherwise, wait for the animation start callback from the activity options @@ -1039,7 +1056,7 @@ constructor( return runnableList } val runnableList = RunnableList() - AnimatorSet().apply { + with(AnimatorSet()) { TaskViewUtils.composeRecentsLaunchAnimator( this, this@TaskView, @@ -1054,7 +1071,7 @@ constructor( addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { - if (firstTask.key.displayId != rootViewDisplayId) { + if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) { launchTaskAnimated() } isClickableAsLiveTile = true @@ -1078,10 +1095,11 @@ constructor( } private fun notifyTaskLaunchFailed() { - Log.w( - TAG, - "Failed to launch task (task=${firstTask.key.baseIntent} userId=${firstTask.key.userId})" - ) + val sb = StringBuilder("Failed to launch task \n") + taskContainers.forEach { + sb.append("(task=${it.task.key.baseIntent} userId=${it.task.key.userId})\n") + } + Log.w(TAG, sb.toString()) Toast.makeText(context, R.string.activity_not_available, Toast.LENGTH_SHORT).show() } @@ -1108,8 +1126,8 @@ constructor( this, container.task, container.iconView.drawable, - container.thumbnailView, - container.thumbnailView.thumbnail, /* intent */ + container.thumbnailViewDeprecated, + container.thumbnailViewDeprecated.thumbnail, /* intent */ null, /* user */ null, container.itemInfo @@ -1172,41 +1190,23 @@ constructor( } } - @Deprecated("Use {@link #getItemInfo(Task)} instead.") - /** Builds proto for logging. */ - fun getItemInfo() = getItemInfo(firstTask) - - /** Builds proto for logging */ - @VisibleForTesting - fun getItemInfo(task: Task): WorkspaceItemInfo { - return WorkspaceItemInfo().apply { - itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK - container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER - val componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key) - user = componentKey.user - intent = Intent().setComponent(componentKey.componentName) - title = task.title - recentsView?.let { screenId = it.indexOfChild(this@TaskView) } - if (privateSpaceRestrictAccessibilityDrag()) { - if (UserCache.getInstance(context).getUserInfo(componentKey.user).isPrivate) { - runtimeStatusFlags = runtimeStatusFlags or ItemInfoWithIcon.FLAG_NOT_PINNABLE - } - } - } - } - /** * Whether the taskview should take the touch event from parent. Events passed to children that * might require special handling. */ open fun offerTouchToChildren(event: MotionEvent): Boolean { - if (event.action == MotionEvent.ACTION_DOWN) { - computeAndSetIconTouchDelegate(iconView, mIconCenterCoordinates, iconTouchDelegate) + taskContainers.forEach { + if (event.action == MotionEvent.ACTION_DOWN) { + computeAndSetIconTouchDelegate(it.iconView, tempCoordinates, it.iconTouchDelegate) + if (it.iconTouchDelegate.onTouchEvent(event)) { + return true + } + } } - return iconTouchDelegate.onTouchEvent(event) + return false } - protected fun computeAndSetIconTouchDelegate( + private fun computeAndSetIconTouchDelegate( view: TaskViewIcon, tempCenterCoordinates: FloatArray, transformingTouchDelegate: TransformingTouchDelegate @@ -1232,10 +1232,14 @@ constructor( /** Sets up an on-click listener and the visibility for show_windows icon on top of the task. */ open fun setUpShowAllInstancesListener() { - val taskPackageName = taskContainers[0].task.key.packageName - // icon of the top/left task - val showWindowsView = findViewById(R.id.show_windows)!! - updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName)) + taskContainers.forEach { + it.showWindowsView?.let { showWindowsView -> + updateFilterCallback( + showWindowsView, + getFilterUpdateCallback(it.task.key.packageName) + ) + } + } } /** @@ -1243,7 +1247,7 @@ constructor( * * @param taskPackageName package name of the task to filter by */ - protected fun getFilterUpdateCallback(taskPackageName: String?) = + private fun getFilterUpdateCallback(taskPackageName: String?) = if (recentsView?.filterState?.shouldShowFilterUI(taskPackageName) == true) OnClickListener { recentsView?.setAndApplyFilter(taskPackageName) } else null @@ -1252,11 +1256,13 @@ constructor( * Sets the correct visibility and callback on the provided filterView based on whether the * callback is null or not */ - protected fun updateFilterCallback(filterView: View, callback: OnClickListener?) { + private fun updateFilterCallback(filterView: View, callback: OnClickListener?) { // Filtering changes alpha instead of the visibility since visibility // can be altered separately through RecentsView#resetFromSplitSelectionState() - filterView.alpha = if (callback == null) 0f else 1f - filterView.setOnClickListener(callback) + with(filterView) { + alpha = if (callback == null) 0f else 1f + setOnClickListener(callback) + } } protected open fun setIconsAndBannersFullscreenProgress(progress: Float) { @@ -1275,12 +1281,14 @@ constructor( protected open fun setIconsAndBannersTransitionProgress(progress: Float, invert: Boolean) { focusTransitionProgress = if (invert) 1 - progress else progress getIconContentScale(invert).let { iconContentScale -> - iconView.setContentAlpha(iconContentScale) - digitalWellBeingToast.updateBannerOffset(1f - iconContentScale) + taskContainers.forEach { + it.iconView.setContentAlpha(iconContentScale) + it.digitalWellBeingToast?.updateBannerOffset(1f - iconContentScale) + } } } - protected fun getIconContentScale(invert: Boolean): Float { + private fun getIconContentScale(invert: Boolean): Float { val iconScalePercentage = SCALE_ICON_DURATION.toFloat() / DIM_ANIM_DURATION val lowerClamp = if (invert) 1f - iconScalePercentage else 0f val upperClamp = if (invert) 1f else iconScalePercentage @@ -1312,12 +1320,14 @@ constructor( /** Set a color tint on the snapshot and supporting views. */ open fun setColorTint(amount: Float, tintColor: Int) { - if (!enableRefactorTaskThumbnail()) { - // TODO(b/334832108) Add scrim to new TTV - taskThumbnailViewDeprecated.setDimAlpha(amount) + taskContainers.forEach { + if (!enableRefactorTaskThumbnail()) { + // TODO(b/334832108) Add scrim to new TTV + it.thumbnailViewDeprecated.dimAlpha = amount + } + it.iconView.setIconColorTint(tintColor, amount) + it.digitalWellBeingToast?.setBannerColorTint(tintColor, amount) } - iconView.setIconColorTint(tintColor, amount) - digitalWellBeingToast.setBannerColorTint(tintColor, amount) } /** @@ -1327,21 +1337,28 @@ constructor( * @param taskId is only used when setting visibility to a non-[View.VISIBLE] value */ open fun setThumbnailVisibility(visibility: Int, taskId: Int) { - children.filterNot { it === iconView }.forEach { it.visibility = visibility } + taskContainers.forEach { + if (visibility == VISIBLE || it.task.key.id == taskId) { + it.snapshotView.visibility = visibility + it.digitalWellBeingToast?.setBannerVisibility(visibility) + it.showWindowsView?.visibility = visibility + it.overlay.setVisibility(visibility) + } + } } open fun setOverlayEnabled(overlayEnabled: Boolean) { // 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()) { - taskThumbnailViewDeprecated.setOverlayEnabled(overlayEnabled) + taskContainers.forEach { it.thumbnailViewDeprecated.setOverlayEnabled(overlayEnabled) } } } protected open fun refreshTaskThumbnailSplash() { if (!enableRefactorTaskThumbnail()) { // TODO(b/334826842) add splash functionality to new TTV - taskThumbnailViewDeprecated.refreshSplashView() + taskContainers.forEach { it.thumbnailViewDeprecated.refreshSplashView() } } } @@ -1365,7 +1382,9 @@ constructor( protected open fun applyThumbnailSplashAlpha() { if (!enableRefactorTaskThumbnail()) { // TODO(b/334826842) add splash functionality to new TTV - taskThumbnailViewDeprecated.setSplashAlpha(taskThumbnailSplashAlpha) + taskContainers.forEach { + it.thumbnailViewDeprecated.setSplashAlpha(taskThumbnailSplashAlpha) + } } } @@ -1395,18 +1414,23 @@ constructor( } protected open fun onFullscreenProgressChanged(fullscreenProgress: Float) { - iconView.setVisibility(if (fullscreenProgress < 1) VISIBLE else INVISIBLE) - taskThumbnailViewDeprecated.taskOverlay.setFullscreenProgress(fullscreenProgress) + taskContainers.forEach { + it.iconView.setVisibility(if (fullscreenProgress < 1) VISIBLE else INVISIBLE) + it.overlay.setFullscreenProgress(fullscreenProgress) + } setIconsAndBannersFullscreenProgress(fullscreenProgress) updateSnapshotRadius() } protected open fun updateSnapshotRadius() { updateCurrentFullscreenParams() - taskThumbnailViewDeprecated.setFullscreenParams(currentFullscreenParams) + taskContainers.forEach { + it.thumbnailViewDeprecated.setFullscreenParams(getThumbnailFullscreenParams()) + it.overlay.setFullscreenParams(getThumbnailFullscreenParams()) + } } - protected fun updateCurrentFullscreenParams() { + protected open fun updateCurrentFullscreenParams() { updateFullscreenParams(currentFullscreenParams) } @@ -1414,18 +1438,21 @@ constructor( recentsView?.let { fullscreenParams.setProgress(fullscreenProgress, it.scaleX, scaleX) } } + protected open fun getThumbnailFullscreenParams(): FullscreenDrawParams = + currentFullscreenParams + private fun onModalnessUpdated(modalness: Float) { - iconView.setModalAlpha(1 - modalness) - digitalWellBeingToast.updateBannerOffset(modalness) + taskContainers.forEach { + it.iconView.setModalAlpha(1 - modalness) + it.digitalWellBeingToast?.updateBannerOffset(modalness) + } } /** Updates [TaskThumbnailView] to reflect the latest [Task] state (i.e., task isRunning). */ fun 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 (taskContainers.isNotEmpty()) { - bindTaskThumbnailView() - } + taskContainers.forEach { it.bindThumbnailView() } } fun resetPersistentViewTransforms() { @@ -1458,7 +1485,7 @@ constructor( setColorTint(0f, 0) if (!enableRefactorTaskThumbnail()) { // TODO(b/335399428) add split select functionality to new TTV - taskThumbnailViewDeprecated.resetViewTransforms() + taskContainers.forEach { it.thumbnailViewDeprecated.resetViewTransforms() } } } @@ -1508,21 +1535,61 @@ constructor( /** Holder for all Task dependent information. */ inner class TaskContainer( val task: Task, - val thumbnailView: TaskThumbnailViewDeprecated, + val thumbnailView: TaskThumbnailView?, + val thumbnailViewDeprecated: TaskThumbnailViewDeprecated, val iconView: TaskViewIcon, + /** + * This technically can be a vanilla [android.view.TouchDelegate] class, however that class + * requires setting the touch bounds at construction, so we'd repeatedly be created many + * instances unnecessarily as scrolling occurs, whereas [TransformingTouchDelegate] allows + * touch delegated bounds only to be updated. + */ + val iconTouchDelegate: TransformingTouchDelegate, /** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */ - @field:StagePosition var stagePosition: Int, - val digitalWellBeingToast: DigitalWellBeingToast? + @StagePosition val stagePosition: Int, + val digitalWellBeingToast: DigitalWellBeingToast?, + val showWindowsView: View?, + taskOverlayFactory: TaskOverlayFactory ) { + val overlay: TaskOverlay<*> = taskOverlayFactory.createOverlay(this) + @IdRes val a11yNodeId: Int = if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) R.id.split_bottomRight_appInfo else R.id.split_topLeft_appInfo + val snapshotView: View + get() = thumbnailView ?: thumbnailViewDeprecated + + /** Builds proto for logging */ val itemInfo: WorkspaceItemInfo - get() = getItemInfo(task) + get() = + WorkspaceItemInfo().apply { + itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK + container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER + val componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key) + user = componentKey.user + intent = Intent().setComponent(componentKey.componentName) + title = task.title + recentsView?.let { screenId = it.indexOfChild(this@TaskView) } + if (privateSpaceRestrictAccessibilityDrag()) { + if ( + UserCache.getInstance(context).getUserInfo(componentKey.user).isPrivate + ) { + runtimeStatusFlags = + runtimeStatusFlags or ItemInfoWithIcon.FLAG_NOT_PINNABLE + } + } + } + val taskView: TaskView get() = this@TaskView + + // 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 + fun bindThumbnailView() { + thumbnailView?.viewModel?.bind(TaskThumbnail(task, isRunningTask)) + } } companion object { diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt index 33a8e7976b..36f2ccf5be 100644 --- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt +++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt @@ -19,7 +19,7 @@ package com.android.quickstep import android.content.ComponentName import android.content.Intent import android.platform.test.flag.junit.SetFlagsRule -import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn +import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.launcher3.AbstractFloatingView @@ -29,6 +29,8 @@ import com.android.launcher3.logging.StatsLogManager.LauncherEvent import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.uioverrides.QuickstepLauncher import com.android.launcher3.util.SplitConfigurationOptions +import com.android.launcher3.util.TransformingTouchDelegate +import com.android.quickstep.TaskOverlayFactory.TaskOverlay import com.android.quickstep.views.LauncherRecentsView import com.android.quickstep.views.TaskThumbnailViewDeprecated import com.android.quickstep.views.TaskView @@ -43,8 +45,10 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.spy import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.mockito.quality.Strictness @@ -61,10 +65,13 @@ class DesktopSystemShortcutTest { private val taskView: TaskView = mock() private val workspaceItemInfo: WorkspaceItemInfo = mock() private val abstractFloatingViewHelper: AbstractFloatingViewHelper = mock() - private val thumbnailView: TaskThumbnailViewDeprecated = mock() + private val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = mock() private val iconView: TaskViewIcon = mock() + private val transformingTouchDelegate: TransformingTouchDelegate = mock() private val factory: TaskShortcutFactory = DesktopSystemShortcut.createFactory(abstractFloatingViewHelper) + private val overlayFactory: TaskOverlayFactory = mock() + private val overlay: TaskOverlay<*> = mock() private lateinit var mockitoSession: StaticMockitoSession @@ -75,8 +82,9 @@ class DesktopSystemShortcutTest { .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .startMocking() - doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() } - doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + ExtendedMockito.doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() } + ExtendedMockito.doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + whenever(overlayFactory.createOverlay(any())).thenReturn(overlay) } @After @@ -92,14 +100,7 @@ class DesktopSystemShortcutTest { Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { isDockable = true } - val taskContainer = - taskView.TaskContainer( - task, - thumbnailView, - iconView, - SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, - null - ) + val taskContainer = createTaskContainer(task) val shortcuts = factory.getShortcuts(launcher, taskContainer) assertThat(shortcuts).isNull() @@ -108,20 +109,9 @@ class DesktopSystemShortcutTest { @Test fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported() { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } - val task = - Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { - isDockable = true - } - val taskContainer = - taskView.TaskContainer( - task, - thumbnailView, - iconView, - SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, - null - ) + val taskContainer = createTaskContainer(createTask()) val shortcuts = factory.getShortcuts(launcher, taskContainer) assertThat(shortcuts).isNull() @@ -130,21 +120,11 @@ class DesktopSystemShortcutTest { @Test fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported_OverrideEnabled() { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } - doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() } + ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() } - val task = - Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { - isDockable = true - } - val taskContainer = - taskView.TaskContainer( - task, - thumbnailView, - iconView, - SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, - null - ) + val taskContainer = spy(createTaskContainer(createTask())) + doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo val shortcuts = factory.getShortcuts(launcher, taskContainer) assertThat(shortcuts).isNotNull() @@ -154,18 +134,8 @@ class DesktopSystemShortcutTest { fun createDesktopTaskShortcutFactory_undockable() { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - val task = - Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { - isDockable = false - } - val taskContainer = - taskView.TaskContainer( - task, - thumbnailView, - iconView, - SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, - null - ) + val unDockableTask = createTask().apply { isDockable = false } + val taskContainer = createTaskContainer(unDockableTask) val shortcuts = factory.getShortcuts(launcher, taskContainer) assertThat(shortcuts).isNull() @@ -175,28 +145,18 @@ class DesktopSystemShortcutTest { fun desktopSystemShortcutClicked() { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - val task = - Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { - isDockable = true - } - val taskContainer = - taskView.TaskContainer( - task, - thumbnailView, - iconView, - SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, - null - ) + val task = createTask() + val taskContainer = spy(createTaskContainer(task)) whenever(launcher.getOverviewPanel()).thenReturn(recentsView) whenever(launcher.statsLogManager).thenReturn(statsLogManager) whenever(statsLogManager.logger()).thenReturn(statsLogger) whenever(statsLogger.withItemInfo(any())).thenReturn(statsLogger) - whenever(taskView.getItemInfo(task)).thenReturn(workspaceItemInfo) whenever(recentsView.moveTaskToDesktop(any(), any())).thenAnswer { val successCallback = it.getArgument(1) successCallback.run() } + doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo val shortcuts = factory.getShortcuts(launcher, taskContainer) assertThat(shortcuts).hasSize(1) @@ -213,4 +173,24 @@ class DesktopSystemShortcutTest { verify(statsLogger).withItemInfo(workspaceItemInfo) verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP) } + + private fun createTask(): Task { + return Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { + isDockable = true + } + } + + private fun createTaskContainer(task: Task): TaskView.TaskContainer { + return taskView.TaskContainer( + task, + thumbnailView = null, + thumbnailViewDeprecated, + iconView, + transformingTouchDelegate, + SplitConfigurationOptions.STAGE_POSITION_UNDEFINED, + digitalWellBeingToast = null, + showWindowsView = null, + overlayFactory + ) + } } diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java index 37ab1319b7..07d8f61992 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java @@ -86,9 +86,10 @@ public class TaplDigitalWellBeingToastTest extends AbstractQuickStepTest { final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher)); return getFromLauncher(launcher -> { + TaskView.TaskContainer taskContainer = task.getTaskContainers().get(0); assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals( - task.getFirstTask().getTopComponent().getPackageName())); - return task.getDigitalWellBeingToast(); + taskContainer.getTask().getTopComponent().getPackageName())); + return taskContainer.getDigitalWellBeingToast(); }); } diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt index f29df613cd..250dc7b924 100644 --- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt +++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt @@ -87,7 +87,7 @@ class SplitAnimationControllerTest { @Before fun setup() { - whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView) + whenever(mockTaskContainer.thumbnailViewDeprecated).thenReturn(mockThumbnailView) whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap) whenever(mockTaskContainer.iconView).thenReturn(mockIconView) whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable) @@ -180,7 +180,7 @@ class SplitAnimationControllerTest { whenever(mockTaskContainer.task).thenReturn(mockTask) whenever(mockTaskContainer.iconView).thenReturn(mockIconView) - whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView) + whenever(mockTaskContainer.thumbnailViewDeprecated).thenReturn(mockThumbnailView) whenever(mockTask.getKey()).thenReturn(mockTaskKey) whenever(mockTaskKey.getId()).thenReturn(taskId) whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId) diff --git a/src/com/android/launcher3/util/rects/Rects.kt b/src/com/android/launcher3/util/rects/Rects.kt index ac1f3f85f2..1e6d7174cd 100644 --- a/src/com/android/launcher3/util/rects/Rects.kt +++ b/src/com/android/launcher3/util/rects/Rects.kt @@ -21,5 +21,6 @@ import android.view.View /** Copy the coordinates of the [view] relative to its parent into this rectangle. */ fun Rect.set(view: View) { - set(view.left, view.top, view.right, view.bottom) + set(0, 0, view.width, view.height) + offset(view.x.toInt(), view.y.toInt()) }