diff --git a/quickstep/Android.bp b/quickstep/Android.bp index 1b9c661387..4c724dc290 100644 --- a/quickstep/Android.bp +++ b/quickstep/Android.bp @@ -52,6 +52,7 @@ filegroup { "tests/src/com/android/quickstep/TaplOverviewIconTest.java", "tests/src/com/android/quickstep/TaplTestsQuickstep.java", "tests/src/com/android/quickstep/TaplTestsSplitscreen.java", + "tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt", "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java", ], } diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml index 6a99a3bca8..3973e56f4a 100644 --- a/quickstep/res/layout/digital_wellbeing_toast.xml +++ b/quickstep/res/layout/digital_wellbeing_toast.xml @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - + + \ No newline at end of file diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml index cb4b98fd4c..00a990b177 100644 --- a/quickstep/res/layout/task_grouped.xml +++ b/quickstep/res/layout/task_grouped.xml @@ -73,4 +73,12 @@ android:inflatedId="@id/bottomRight_icon" android:layout_height="wrap_content" android:layout_width="wrap_content" /> + + + + \ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 56f88d12f5..60e65b34a2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -152,12 +152,12 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * How long to delay the icon/stash handle alpha. */ - private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33; + public static final long TASKBAR_STASH_ALPHA_START_DELAY = 33; /** * How long the icon/stash handle alpha animation plays. */ - private static final long TASKBAR_STASH_ALPHA_DURATION = 50; + public static final long TASKBAR_STASH_ALPHA_DURATION = 50; /** * How long to delay the icon/stash handle alpha for the home to app taskbar animation. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt index 76ed3fc22a..8d632173a0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt @@ -179,9 +179,6 @@ interface BubbleStashController { /** How long to stash/unstash. */ const val BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE.toLong() - const val BAR_STASH_ALPHA_DURATION = 50L - const val BAR_STASH_ALPHA_DELAY = 33L - /** How long to translate Y coordinate of the BubbleBar. */ const val BAR_TRANSLATION_DURATION = 300L } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt index 6787b3fc40..1157305d08 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt @@ -31,10 +31,10 @@ import com.android.launcher3.R import com.android.launcher3.anim.AnimatedFloat import com.android.launcher3.anim.SpringAnimationBuilder import com.android.launcher3.taskbar.TaskbarInsetsController +import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_DURATION +import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY import com.android.launcher3.taskbar.bubbles.BubbleBarViewController import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController -import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_ALPHA_DELAY -import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_ALPHA_DURATION import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction @@ -285,8 +285,8 @@ class TransientBubbleStashController( private fun createStashAnimator(isStashed: Boolean, duration: Long): AnimatorSet { val animatorSet = AnimatorSet() - val alphaDuration = if (isStashed) duration else BAR_STASH_ALPHA_DURATION - val alphaDelay = if (isStashed) BAR_STASH_ALPHA_DELAY else 0L + val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION + val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L animatorSet.play( createStashAlphaAnimator(isStashed).apply { this.duration = max(0L, alphaDuration - alphaDelay) diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt index ec04cb767d..658975c4a9 100644 --- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt @@ -37,6 +37,7 @@ import android.widget.LinearLayout import androidx.annotation.VisibleForTesting import androidx.core.util.component1 import androidx.core.util.component2 +import androidx.core.view.updateLayoutParams import com.android.launcher3.DeviceProfile import com.android.launcher3.Flags import com.android.launcher3.LauncherAnimUtils @@ -242,7 +243,30 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { lp.height = ViewGroup.LayoutParams.WRAP_CONTENT } - override fun getDwbLayoutTranslations( + override fun updateDwbBannerLayout( + taskViewWidth: Int, + taskViewHeight: Int, + isGroupedTaskView: Boolean, + deviceProfile: DeviceProfile, + snapshotViewWidth: Int, + snapshotViewHeight: Int, + banner: View + ) { + banner.pivotX = 0f + banner.pivotY = 0f + banner.rotation = degreesRotated + banner.updateLayoutParams { + gravity = Gravity.TOP or if (banner.isLayoutRtl) Gravity.END else Gravity.START + width = + if (isGroupedTaskView) { + snapshotViewHeight + } else { + taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx + } + } + } + + override fun getDwbBannerTranslations( taskViewWidth: Int, taskViewHeight: Int, splitBounds: SplitBounds?, @@ -252,39 +276,25 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { banner: View ): Pair { val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams - val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL val translationX = banner.height.toFloat() - - val bannerParams = banner.layoutParams as FrameLayout.LayoutParams - bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START - banner.pivotX = 0f - banner.pivotY = 0f - banner.rotation = degreesRotated - - if (splitBounds == null) { - // Single, fullscreen case - bannerParams.width = taskViewHeight - snapshotParams.topMargin - return Pair(translationX, snapshotParams.topMargin.toFloat()) - } - - // Set correct width and translations val translationY: Float - if (desiredTaskId == splitBounds.leftTopTaskId) { - bannerParams.width = thumbnailViews[0].measuredHeight + if (splitBounds == null) { translationY = snapshotParams.topMargin.toFloat() } else { - bannerParams.width = thumbnailViews[1].measuredHeight - val topLeftTaskPlusDividerPercent = - if (splitBounds.appsStackedVertically) { - splitBounds.topTaskPercent + splitBounds.dividerHeightPercent - } else { - splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent - } - translationY = - snapshotParams.topMargin + - (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent + if (desiredTaskId == splitBounds.leftTopTaskId) { + translationY = snapshotParams.topMargin.toFloat() + } else { + val topLeftTaskPlusDividerPercent = + if (splitBounds.appsStackedVertically) { + splitBounds.topTaskPercent + splitBounds.dividerHeightPercent + } else { + splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent + } + translationY = + snapshotParams.topMargin + + (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent + } } - return Pair(translationX, translationY) } @@ -300,6 +310,7 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { if (isRtl) displacement < 0 else displacement > 0 override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1 + /* -------------------- */ override fun getChildBounds( diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java index eeacee1cf6..32d9052e3a 100644 --- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java +++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java @@ -243,54 +243,54 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements } @Override - public Pair getDwbLayoutTranslations(int taskViewWidth, - int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile, - View[] thumbnailViews, int desiredTaskId, View banner) { - float translationX = 0; - float translationY = 0; + public void updateDwbBannerLayout(int taskViewWidth, int taskViewHeight, + boolean isGroupedTaskView, @NonNull DeviceProfile deviceProfile, + int snapshotViewWidth, int snapshotViewHeight, @NonNull View banner) { FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams(); banner.setPivotX(0); banner.setPivotY(0); banner.setRotation(getDegreesRotated()); - if (splitBounds == null) { - // Single, fullscreen case + if (isGroupedTaskView) { + bannerParams.gravity = + BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL); + bannerParams.width = snapshotViewWidth; + } else { bannerParams.width = MATCH_PARENT; bannerParams.gravity = BOTTOM | CENTER_HORIZONTAL; - return new Pair<>(translationX, translationY); } + banner.setLayoutParams(bannerParams); + } - bannerParams.gravity = - BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL); - - // Set correct width - if (desiredTaskId == splitBounds.leftTopTaskId) { - bannerParams.width = thumbnailViews[0].getMeasuredWidth(); - } else { - bannerParams.width = thumbnailViews[1].getMeasuredWidth(); - } - - // Set translations - if (deviceProfile.isLeftRightSplit) { - if (desiredTaskId == splitBounds.rightBottomTaskId) { - float leftTopTaskPercent = splitBounds.appsStackedVertically - ? splitBounds.topTaskPercent - : splitBounds.leftTaskPercent; - float dividerThicknessPercent = splitBounds.appsStackedVertically - ? splitBounds.dividerHeightPercent - : splitBounds.dividerWidthPercent; - translationX = ((taskViewWidth * leftTopTaskPercent) - + (taskViewWidth * dividerThicknessPercent)); - } - } else { - if (desiredTaskId == splitBounds.leftTopTaskId) { - FrameLayout.LayoutParams snapshotParams = - (FrameLayout.LayoutParams) thumbnailViews[0] - .getLayoutParams(); - float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically - ? (1f - splitBounds.topTaskPercent) - : (1f - splitBounds.leftTaskPercent); - translationY = -((taskViewHeight - snapshotParams.topMargin) - * bottomRightTaskPlusDividerPercent); + @NonNull + @Override + public Pair getDwbBannerTranslations(int taskViewWidth, + int taskViewHeight, SplitBounds splitBounds, @NonNull DeviceProfile deviceProfile, + @NonNull View[] thumbnailViews, int desiredTaskId, @NonNull View banner) { + float translationX = 0; + float translationY = 0; + if (splitBounds != null) { + if (deviceProfile.isLeftRightSplit) { + if (desiredTaskId == splitBounds.rightBottomTaskId) { + float leftTopTaskPercent = splitBounds.appsStackedVertically + ? splitBounds.topTaskPercent + : splitBounds.leftTaskPercent; + float dividerThicknessPercent = splitBounds.appsStackedVertically + ? splitBounds.dividerHeightPercent + : splitBounds.dividerWidthPercent; + translationX = ((taskViewWidth * leftTopTaskPercent) + + (taskViewWidth * dividerThicknessPercent)); + } + } else { + if (desiredTaskId == splitBounds.leftTopTaskId) { + FrameLayout.LayoutParams snapshotParams = + (FrameLayout.LayoutParams) thumbnailViews[0] + .getLayoutParams(); + float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically + ? (1f - splitBounds.topTaskPercent) + : (1f - splitBounds.leftTaskPercent); + translationY = -((taskViewHeight - snapshotParams.topMargin) + * bottomRightTaskPlusDividerPercent); + } } } return new Pair<>(translationX, translationY); diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt index df4b03038f..06a0685d6c 100644 --- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt @@ -199,6 +199,7 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { parentWidth: Int, parentHeight: Int ): Pair + // Overview TaskMenuView methods /** Sets layout params on a task's app icon. Only use this when app chip is disabled. */ fun setTaskIconParams( @@ -294,13 +295,24 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { deviceProfile: DeviceProfile ) + /** Layout a Digital Wellbeing Banner on its parent. TaskView. */ + fun updateDwbBannerLayout( + taskViewWidth: Int, + taskViewHeight: Int, + isGroupedTaskView: Boolean, + deviceProfile: DeviceProfile, + snapshotViewWidth: Int, + snapshotViewHeight: Int, + banner: View + ) + /** - * Calculates the position where a Digital Wellbeing Banner should be placed on its parent + * Calculates the translations where a Digital Wellbeing Banner should be apply on its parent * TaskView. * * @return A Pair of Floats representing the proper x and y translations. */ - fun getDwbLayoutTranslations( + fun getDwbBannerTranslations( taskViewWidth: Int, taskViewHeight: Int, splitBounds: SplitConfigurationOptions.SplitBounds?, @@ -309,6 +321,7 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { desiredTaskId: Int, banner: View ): Pair + // The following are only used by TaskViewTouchHandler. /** @return Either VERTICAL or HORIZONTAL. */ diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt index 333359fdd8..a972e8c1ef 100644 --- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt @@ -28,6 +28,7 @@ import android.view.View.MeasureSpec import android.widget.FrameLayout import androidx.core.util.component1 import androidx.core.util.component2 +import androidx.core.view.updateLayoutParams import com.android.launcher3.DeviceProfile import com.android.launcher3.Flags import com.android.launcher3.R @@ -125,7 +126,30 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { } } - override fun getDwbLayoutTranslations( + override fun updateDwbBannerLayout( + taskViewWidth: Int, + taskViewHeight: Int, + isGroupedTaskView: Boolean, + deviceProfile: DeviceProfile, + snapshotViewWidth: Int, + snapshotViewHeight: Int, + banner: View + ) { + banner.pivotX = 0f + banner.pivotY = 0f + banner.rotation = degreesRotated + banner.updateLayoutParams { + gravity = Gravity.BOTTOM or if (banner.isLayoutRtl) Gravity.END else Gravity.START + width = + if (isGroupedTaskView) { + snapshotViewHeight + } else { + taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx + } + } + } + + override fun getDwbBannerTranslations( taskViewWidth: Int, taskViewHeight: Int, splitBounds: SplitBounds?, @@ -135,39 +159,26 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { banner: View ): Pair { val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams - val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL - - val bannerParams = banner.layoutParams as FrameLayout.LayoutParams - bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START - banner.pivotX = 0f - banner.pivotY = 0f - banner.rotation = degreesRotated - val translationX: Float = (taskViewWidth - banner.height).toFloat() - if (splitBounds == null) { - // Single, fullscreen case - bannerParams.width = taskViewHeight - snapshotParams.topMargin - return Pair(translationX, banner.height.toFloat()) - } - - // Set correct width and translations val translationY: Float - if (desiredTaskId == splitBounds.leftTopTaskId) { - bannerParams.width = thumbnailViews[0].measuredHeight - val bottomRightTaskPlusDividerPercent = - if (splitBounds.appsStackedVertically) { - 1f - splitBounds.topTaskPercent - } else { - 1f - splitBounds.leftTaskPercent - } - translationY = - banner.height - - (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent - } else { - bannerParams.width = thumbnailViews[1].measuredHeight + if (splitBounds == null) { translationY = banner.height.toFloat() + } else { + if (desiredTaskId == splitBounds.leftTopTaskId) { + val bottomRightTaskPlusDividerPercent = + if (splitBounds.appsStackedVertically) { + 1f - splitBounds.topTaskPercent + } else { + 1f - splitBounds.leftTaskPercent + } + translationY = + banner.height - + (taskViewHeight - snapshotParams.topMargin) * + bottomRightTaskPlusDividerPercent + } else { + translationY = banner.height.toFloat() + } } - return Pair(translationX, translationY) } @@ -339,6 +350,7 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { if (isRtl) displacement > 0 else displacement < 0 override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1 + /* -------------------- */ override fun getSplitIconsPosition( diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt index 0ab36c9d72..f0fdd8147e 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt @@ -15,8 +15,10 @@ */ package com.android.quickstep.views +import android.annotation.SuppressLint import android.app.ActivityOptions import android.content.ActivityNotFoundException +import android.content.Context import android.content.Intent import android.content.pm.LauncherApps import android.content.pm.LauncherApps.AppUsageLimit @@ -27,46 +29,58 @@ import android.icu.util.Measure import android.icu.util.MeasureUnit import android.os.UserHandle import android.provider.Settings +import android.util.AttributeSet import android.util.Log import android.view.View -import android.view.ViewGroup.MarginLayoutParams import android.view.ViewOutlineProvider import android.view.accessibility.AccessibilityNodeInfo -import android.widget.FrameLayout import android.widget.TextView import androidx.annotation.StringRes +import androidx.annotation.VisibleForTesting import androidx.core.util.component1 import androidx.core.util.component2 -import androidx.core.view.updateLayoutParams import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.launcher3.util.Executors import com.android.launcher3.util.SplitConfigurationOptions +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.SplitConfigurationOptions.StagePosition import com.android.quickstep.TaskUtils import com.android.systemui.shared.recents.model.Task import java.time.Duration import java.util.Locale -class DigitalWellBeingToast( - private val container: RecentsViewContainer, - private val taskView: TaskView -) { - private val launcherApps: LauncherApps? = - container.asContext().getSystemService(LauncherApps::class.java) +@SuppressLint("AppCompatCustomView") +class DigitalWellBeingToast +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : TextView(context, attrs, defStyleAttr, defStyleRes) { + private val recentsViewContainer = + RecentsViewContainer.containerFromContext(context) + + private val launcherApps: LauncherApps? = context.getSystemService(LauncherApps::class.java) private val bannerHeight = - container - .asContext() - .resources - .getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height) + context.resources.getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height) private lateinit var task: Task + private lateinit var taskView: TaskView + private lateinit var snapshotView: View + @StagePosition private var stagePosition = STAGE_POSITION_UNDEFINED private var appRemainingTimeMs: Long = 0 - private var banner: View? = null - private var oldBannerOutlineProvider: ViewOutlineProvider? = null private var splitOffsetTranslationY = 0f - private var splitOffsetTranslationX = 0f + set(value) { + if (field != value) { + field = value + updateTranslationY() + } + } private var isDestroyed = false @@ -76,65 +90,63 @@ class DigitalWellBeingToast( set(value) { if (field != value) { field = value - banner?.let { - updateTranslationY() - it.invalidateOutline() - } + updateTranslationY() } } + init { + setOnClickListener(::openAppUsageSettings) + outlineProvider = + object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { + BACKGROUND.getOutline(view, outline) + val verticalTranslation = splitOffsetTranslationY - translationY + outline.offset(0, Math.round(verticalTranslation)) + } + } + clipToOutline = true + } + private fun setNoLimit() { hasLimit = false - taskView.contentDescription = task.titleDescription - replaceBanner(null) + setContentDescription(appUsageLimitTimeMs = -1, appRemainingTimeMs = -1) + visibility = INVISIBLE appRemainingTimeMs = -1 } private fun setLimit(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) { this.appRemainingTimeMs = appRemainingTimeMs hasLimit = true - val toast = - container.viewCache - .getView( - R.layout.digital_wellbeing_toast, - container.asContext(), - taskView - ) - .apply { - text = - Utilities.prefixTextWithIcon( - container.asContext(), - R.drawable.ic_hourglass_top, - getBannerText() - ) - setOnClickListener(::openAppUsageSettings) - } - replaceBanner(toast) - - taskView.contentDescription = - getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs) + text = Utilities.prefixTextWithIcon(context, R.drawable.ic_hourglass_top, getBannerText()) + visibility = VISIBLE + setContentDescription(appUsageLimitTimeMs, appRemainingTimeMs) } - fun initialize(task: Task) { + private fun setContentDescription(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) { + val contentDescription = + getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs) + snapshotView.contentDescription = contentDescription + } + + fun initialize() { check(!isDestroyed) { "Cannot re-initialize a destroyed toast" } - this.task = task + setupTranslations() Executors.ORDERED_BG_EXECUTOR.execute { var usageLimit: AppUsageLimit? = null try { usageLimit = launcherApps?.getAppUsageLimit( - this.task.topComponent.packageName, - UserHandle.of(this.task.key.userId) + task.topComponent.packageName, + UserHandle.of(task.key.userId) ) } catch (e: Exception) { Log.e(TAG, "Error initializing digital well being toast", e) } val appUsageLimitTimeMs = usageLimit?.totalUsageLimit ?: -1 val appRemainingTimeMs = usageLimit?.usageRemaining ?: -1 + taskView.post { - if (isDestroyed) { - return@post - } + if (isDestroyed) return@post if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) { setNoLimit() } else { @@ -144,20 +156,36 @@ class DigitalWellBeingToast( } } - /** Mark the DWB toast as destroyed and remove banner from TaskView. */ + /** Bind the DWB toast to its dependencies. */ + fun bind( + task: Task, + taskView: TaskView, + snapshotView: View, + @StagePosition stagePosition: Int + ) { + this.task = task + this.taskView = taskView + this.snapshotView = snapshotView + this.stagePosition = stagePosition + isDestroyed = false + } + + /** Mark the DWB toast as destroyed and hide it. */ fun destroy() { + visibility = INVISIBLE isDestroyed = true - taskView.post { replaceBanner(null) } } private fun getSplitBannerConfig(): SplitBannerConfig { val splitBounds = splitBounds return when { - splitBounds == null || !container.deviceProfile.isTablet || taskView.isLargeTile -> - SplitBannerConfig.SPLIT_BANNER_FULLSCREEN + splitBounds == null || + !recentsViewContainer.deviceProfile.isTablet || + taskView.isLargeTile -> SplitBannerConfig.SPLIT_BANNER_FULLSCREEN // For portrait grid only height of task changes, not width. So we keep the text the // same - !container.deviceProfile.isLeftRightSplit -> SplitBannerConfig.SPLIT_GRID_BANNER_LARGE + !recentsViewContainer.deviceProfile.isLeftRightSplit -> + SplitBannerConfig.SPLIT_GRID_BANNER_LARGE // For landscape grid, for 30% width we only show icon, otherwise show icon and time task.key.id == splitBounds.leftTopTaskId -> if (splitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY) @@ -193,8 +221,7 @@ class DigitalWellBeingToast( MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) .formatMeasures(Measure(minutes, MeasureUnit.MINUTE)) // Use a specific string for usage less than one minute but non-zero. - duration > Duration.ZERO -> - container.asContext().getString(durationLessThanOneMinuteStringId) + duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId) // Otherwise, return 0-minute string. else -> MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) @@ -208,6 +235,7 @@ class DigitalWellBeingToast( * [.SPLIT_BANNER_FULLSCREEN] */ @JvmOverloads + @VisibleForTesting fun getBannerText( remainingTime: Long = appRemainingTimeMs, forContentDesc: Boolean = false @@ -226,7 +254,7 @@ class DigitalWellBeingToast( val splitBannerConfig = getSplitBannerConfig() return when { forContentDesc || splitBannerConfig == SplitBannerConfig.SPLIT_BANNER_FULLSCREEN -> - container.asContext().getString(R.string.time_left_for_app, readableDuration) + context.getString(R.string.time_left_for_app, readableDuration) // show no text splitBannerConfig == SplitBannerConfig.SPLIT_GRID_BANNER_SMALL -> "" // SPLIT_GRID_BANNER_LARGE only show time @@ -241,7 +269,7 @@ class DigitalWellBeingToast( .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) try { val options = ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.width, view.height) - container.asContext().startActivity(intent, options.toBundle()) + context.startActivity(intent, options.toBundle()) // TODO: add WW logging on the app usage settings click. } catch (e: ActivityNotFoundException) { @@ -259,99 +287,77 @@ class DigitalWellBeingToast( appRemainingTimeMs: Long ): String? = if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0) - container - .asContext() - .getString( - R.string.task_contents_description_with_remaining_time, - task.titleDescription, - getBannerText(appRemainingTimeMs, true /* forContentDesc */) - ) + context.getString( + R.string.task_contents_description_with_remaining_time, + task.titleDescription, + getBannerText(appRemainingTimeMs, true /* forContentDesc */) + ) else task.titleDescription - private fun replaceBanner(view: View?) { - resetOldBanner() - setBanner(view) - } - - private fun resetOldBanner() { - val banner = banner ?: return - banner.outlineProvider = oldBannerOutlineProvider - taskView.removeView(banner) - banner.setOnClickListener(null) - container.viewCache.recycleView(R.layout.digital_wellbeing_toast, banner) - } - - private fun setBanner(banner: View?) { - this.banner = banner - if (banner != null && taskView.recentsView != null) { - setupAndAddBanner() - setBannerOutline() + fun setupLayout() { + val snapshotWidth: Int + val snapshotHeight: Int + val splitBounds = splitBounds + if (splitBounds == null) { + snapshotWidth = taskView.layoutParams.width + snapshotHeight = + taskView.layoutParams.height - + recentsViewContainer.deviceProfile.overviewTaskThumbnailTopMarginPx + } else { + val groupedTaskSize = + taskView.pagedOrientationHandler.getGroupedTaskViewSizes( + recentsViewContainer.deviceProfile, + splitBounds, + taskView.layoutParams.width, + taskView.layoutParams.height + ) + if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) { + snapshotWidth = groupedTaskSize.first.x + snapshotHeight = groupedTaskSize.first.y + } else { + snapshotWidth = groupedTaskSize.second.x + snapshotHeight = groupedTaskSize.second.y + } } + taskView.pagedOrientationHandler.updateDwbBannerLayout( + taskView.layoutParams.width, + taskView.layoutParams.height, + taskView is GroupedTaskView, + recentsViewContainer.deviceProfile, + snapshotWidth, + snapshotHeight, + this + ) } - private fun setupAndAddBanner() { - val banner = banner ?: return - banner.updateLayoutParams { - bottomMargin = - (taskView.firstSnapshotView.layoutParams as MarginLayoutParams).bottomMargin - } + private fun setupTranslations() { val (translationX, translationY) = - taskView.pagedOrientationHandler.getDwbLayoutTranslations( - taskView.measuredWidth, - taskView.measuredHeight, + taskView.pagedOrientationHandler.getDwbBannerTranslations( + taskView.layoutParams.width, + taskView.layoutParams.height, splitBounds, - container.deviceProfile, + recentsViewContainer.deviceProfile, taskView.snapshotViews, task.key.id, - banner + this ) - splitOffsetTranslationX = translationX - splitOffsetTranslationY = translationY - updateTranslationY() - updateTranslationX() - taskView.addView(banner) - } - - private fun setBannerOutline() { - val banner = banner ?: return - // TODO(b\273367585) to investigate why mBanner.getOutlineProvider() can be null - val oldBannerOutlineProvider = - if (banner.outlineProvider != null) banner.outlineProvider - else ViewOutlineProvider.BACKGROUND - this.oldBannerOutlineProvider = oldBannerOutlineProvider - - banner.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - oldBannerOutlineProvider.getOutline(view, outline) - val verticalTranslation = -view.translationY + splitOffsetTranslationY - outline.offset(0, Math.round(verticalTranslation)) - } - } - banner.clipToOutline = true + this.translationX = translationX + this.splitOffsetTranslationY = translationY } private fun updateTranslationY() { - banner?.translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY + translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY + invalidateOutline() } - private fun updateTranslationX() { - banner?.translationX = splitOffsetTranslationX - } - - fun setBannerColorTint(color: Int, amount: Float) { - val banner = banner ?: return + fun setColorTint(color: Int, amount: Float) { if (amount == 0f) { - banner.setLayerType(View.LAYER_TYPE_NONE, null) + setLayerType(View.LAYER_TYPE_NONE, null) } val layerPaint = Paint() layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount)) - banner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint) - banner.setLayerPaint(layerPaint) - } - - fun setBannerVisibility(visibility: Int) { - banner?.visibility = visibility + setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint) + setLayerPaint(layerPaint) } private fun getAccessibilityActionId(): Int = @@ -361,9 +367,8 @@ class DigitalWellBeingToast( fun getDWBAccessibilityAction(): AccessibilityNodeInfo.AccessibilityAction? { if (!hasLimit) return null - val context = container.asContext() val label = - if ((taskView.containsMultipleTasks())) + if (taskView.containsMultipleTasks()) context.getString( R.string.split_app_usage_settings, TaskUtils.getTitle(context, task) diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt index ba4d78694c..4fae01e021 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt @@ -115,6 +115,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu R.id.snapshot, R.id.icon, R.id.show_windows, + R.id.digital_wellbeing_toast, STAGE_POSITION_TOP_OR_LEFT, taskOverlayFactory ), @@ -123,6 +124,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu R.id.bottomright_snapshot, R.id.bottomRight_icon, R.id.show_windows_right, + R.id.bottomRight_digital_wellbeing_toast, STAGE_POSITION_BOTTOM_OR_RIGHT, taskOverlayFactory ) @@ -211,7 +213,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu splitBoundsConfig = splitBounds taskContainers.forEach { it.digitalWellBeingToast?.splitBounds = splitBoundsConfig - it.digitalWellBeingToast?.initialize(it.task) + it.digitalWellBeingToast?.initialize() } invalidate() } diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index af32ba2565..d34a93bdf1 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -146,6 +146,7 @@ class TaskContainer( } fun bind() { + digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) if (enableRefactorTaskThumbnail()) { bindThumbnailView() } else { @@ -171,4 +172,18 @@ class TaskContainer( thumbnailViewDeprecated.setOverlayEnabled(enabled) } } + + fun addChildForAccessibility(outChildren: ArrayList) { + addAccessibleChildToList(iconView.asView(), outChildren) + addAccessibleChildToList(snapshotView, outChildren) + showWindowsView?.let { addAccessibleChildToList(it, outChildren) } + } + + private fun addAccessibleChildToList(view: View, outChildren: ArrayList) { + if (view.includeForAccessibility()) { + outChildren.add(view) + } else { + view.addChildrenForAccessibility(outChildren) + } + } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index d2cdfa2bef..a0e957eede 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -702,6 +702,7 @@ constructor( R.id.snapshot, R.id.icon, R.id.show_windows, + R.id.digital_wellbeing_toast, STAGE_POSITION_UNDEFINED, taskOverlayFactory ) @@ -715,6 +716,7 @@ constructor( @IdRes thumbnailViewId: Int, @IdRes iconViewId: Int, @IdRes showWindowViewId: Int, + @IdRes digitalWellbeingBannerId: Int, @StagePosition stagePosition: Int, taskOverlayFactory: TaskOverlayFactory, ): TaskContainer { @@ -730,6 +732,7 @@ constructor( thumbnailViewDeprecated } val iconView = getOrInflateIconView(iconViewId) + val digitalWellBeingToast = findViewById(digitalWellbeingBannerId)!! return TaskContainer( this, task, @@ -737,7 +740,7 @@ constructor( iconView, TransformingTouchDelegate(iconView.asView()), stagePosition, - DigitalWellBeingToast(container, this), + digitalWellBeingToast, findViewById(showWindowViewId)!!, taskOverlayFactory ) @@ -775,7 +778,7 @@ constructor( protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) { taskContainers.forEach { it.overlay.updateOrientationState(orientationState) - it.digitalWellBeingToast?.initialize(it.task) + it.digitalWellBeingToast?.initialize() } } @@ -827,10 +830,8 @@ constructor( } else { nonGridScale = 1f boxTranslationY = 0f - expectedWidth = if (enableOverviewIconMenu()) taskWidth else LayoutParams.MATCH_PARENT - expectedHeight = - if (enableOverviewIconMenu()) taskHeight + thumbnailPadding - else LayoutParams.MATCH_PARENT + expectedWidth = taskWidth + expectedHeight = taskHeight + thumbnailPadding } this.nonGridScale = nonGridScale this.boxTranslationY = boxTranslationY @@ -847,6 +848,7 @@ constructor( taskContainers[0].snapshotView.updateLayoutParams { topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx } + taskContainers.forEach { it.digitalWellBeingToast?.setupLayout() } } /** Returns the thumbnail's bounds, optionally relative to the screen. */ @@ -939,7 +941,7 @@ constructor( if (enableOverviewIconMenu()) { setText(taskContainer.iconView, taskContainer.task.title) } - taskContainer.digitalWellBeingToast?.initialize(taskContainer.task) + taskContainer.digitalWellBeingToast?.initialize() } protected open fun onIconUnloaded(taskContainer: TaskContainer) { @@ -1444,7 +1446,7 @@ constructor( it.thumbnailViewDeprecated.dimAlpha = amount } it.iconView.setIconColorTint(tintColor, amount) - it.digitalWellBeingToast?.setBannerColorTint(tintColor, amount) + it.digitalWellBeingToast?.setColorTint(tintColor, amount) } } @@ -1458,7 +1460,7 @@ constructor( taskContainers.forEach { if (visibility == VISIBLE || it.task.key.id == taskId) { it.snapshotView.visibility = visibility - it.digitalWellBeingToast?.setBannerVisibility(visibility) + it.digitalWellBeingToast?.visibility = visibility it.showWindowsView?.visibility = visibility it.overlay.setVisibility(visibility) } @@ -1662,6 +1664,12 @@ constructor( return thumbnailBounds.contains(x.toInt(), y.toInt()) } + override fun addChildrenForAccessibility(outChildren: ArrayList) { + (if (isLayoutRtl) taskContainers.reversed() else taskContainers).forEach { + it.addChildForAccessibility(outChildren) + } + } + companion object { private const val TAG = "TaskView" const val FLAG_UPDATE_ICON = 1 diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java index 2087016388..9bc1c5981e 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java @@ -15,20 +15,18 @@ */ package com.android.quickstep; -import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL; -import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT; - import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.Intent; import android.platform.test.annotations.PlatinumTest; +import com.android.launcher3.tapl.Overview; import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask; import com.android.launcher3.tapl.OverviewTaskMenu; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.rule.TestStabilityRule; +import com.android.quickstep.util.SplitScreenTestUtils; import org.junit.Test; @@ -70,39 +68,17 @@ public class TaplOverviewIconTest extends AbstractLauncherUiTest LauncherState.OVERVIEW)); // overview.getCurrentTask().dismiss(); -// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals", +// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple +// dismissals", // (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet( // launcher)) <= 1))); @@ -592,7 +590,8 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { if (overview.hasTasks()) { currentTask = overview.getCurrentTask(); assertFalse("Found ExcludeFromRecentsTestActivity after entering Overview from Home", - currentTask.containsContentDescription("ExcludeFromRecents") + currentTask.containsContentDescription( + "ExcludeFromRecents") || currentTask.containsContentDescription(null)); } else { // Presumably the test started with 0 tasks and remains that way after going home. diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java index 733ea4e2cf..daa4ec327a 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java @@ -17,8 +17,6 @@ package com.android.quickstep; import static com.android.launcher3.config.FeatureFlags.enableSplitContextually; -import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL; -import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -33,7 +31,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.launcher3.tapl.Overview; import com.android.launcher3.tapl.Taskbar; import com.android.launcher3.tapl.TaskbarAppIcon; -import com.android.launcher3.util.rule.TestStabilityRule; +import com.android.quickstep.util.SplitScreenTestUtils; import com.android.wm.shell.Flags; import org.junit.After; @@ -110,9 +108,8 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest { assumeTrue("App pairs feature is currently not enabled, no test needed", Flags.enableAppPairs()); - createAndLaunchASplitPair(); + Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher); - Overview overview = mLauncher.goHome().switchToOverview(); if (mLauncher.isGridOnlyOverviewEnabled() || !mLauncher.isTablet()) { assertTrue("Save app pair menu item is missing", overview.getCurrentTask() @@ -156,24 +153,4 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest { TaskbarAppIcon firstApp = taskbar.getAppIcon(firstAppName); firstApp.launchIntoSplitScreen(); } - - private void createAndLaunchASplitPair() { - clearAllRecentTasks(); - - startTestActivity(2); - startTestActivity(3); - - if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) { - mLauncher.goHome().switchToOverview().getOverviewActions() - .clickSplit() - .getTestActivityTask(2) - .open(); - } else { - mLauncher.goHome().switchToOverview().getCurrentTask() - .tapMenu() - .tapSplitMenuItem() - .getCurrentTask() - .open(); - } - } } diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt new file mode 100644 index 0000000000..82361aabb8 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.quickstep.util + +import androidx.test.uiautomator.By +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.launcher3.tapl.Overview +import com.android.launcher3.tapl.OverviewTask +import com.android.launcher3.ui.AbstractLauncherUiTest + +object SplitScreenTestUtils { + + /** Creates 2 tasks and makes a split mode pair. Also asserts the accessibility labels. */ + @JvmStatic + fun createAndLaunchASplitPairInOverview(launcher: LauncherInstrumentation): Overview { + clearAllRecentTasks(launcher) + + AbstractLauncherUiTest.startTestActivity(2) + AbstractLauncherUiTest.startTestActivity(3) + + val overView = launcher.goHome().switchToOverview() + if (launcher.isTablet && !launcher.isGridOnlyOverviewEnabled) { + overView.overviewActions.clickSplit().getTestActivityTask(2).open() + } else { + overView.currentTask.tapMenu().tapSplitMenuItem().currentTask.open() + } + + val overviewWithSplitPair = launcher.goHome().switchToOverview() + val currentTask = overviewWithSplitPair.currentTask + currentTask.containsContentDescription( + By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity3").toString(), + OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT + ) + currentTask.containsContentDescription( + By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity2").toString(), + OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT + ) + return overviewWithSplitPair + } + + private fun clearAllRecentTasks(launcher: LauncherInstrumentation) { + if (launcher.recentTasks.isNotEmpty()) { + launcher.goHome().switchToOverview().dismissAllTasks() + } + } +} diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index ab48a211ca..5433fa7e94 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -284,8 +284,9 @@ public final class OverviewTask { * * TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed. */ - public boolean containsContentDescription(@Nullable String expected) { - String actual = mTask.getContentDescription(); + public boolean containsContentDescription(@Nullable String expected, + OverviewSplitTask overviewSplitTask) { + String actual = findObjectInTask(overviewSplitTask.snapshotRes).getContentDescription(); if (actual == null && expected == null) { return true; } @@ -295,6 +296,14 @@ public final class OverviewTask { return actual.contains(expected); } + /** + * Returns whether the given String is contained in this Task's contentDescription. Also returns + * true if both Strings are null + */ + public boolean containsContentDescription(@Nullable String expected) { + return containsContentDescription(expected, DEFAULT); + } + private TaskViewType getType() { String resourceName = mTask.getResourceName(); if (resourceName.endsWith("task_view_grouped")) {