diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index cc3b30e9dc..46c1332651 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,7 +28,7 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
-
+
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index 87a0f7073f..708aa3cbd6 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,9 +33,9 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
-
+
-
-
\ No newline at end of file
+ android:layout_height="match_parent">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/task_thumbnail_deprecated.xml b/quickstep/res/layout/task_thumbnail_deprecated.xml
new file mode 100644
index 0000000000..f1a3d62021
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail_deprecated.xml
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/LiveTileView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/LiveTileView.kt
new file mode 100644
index 0000000000..45b368709a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/LiveTileView.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.util.AttributeSet
+import android.view.View
+
+class LiveTileView : View {
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ override fun onDraw(canvas: Canvas) {
+ canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+ }
+
+ companion object {
+ private val CLEAR_PAINT =
+ Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 22d49c12fe..c71b9e74dc 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -18,17 +18,17 @@ package com.android.quickstep.task.thumbnail
import android.content.Context
import android.content.res.Configuration
-import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Outline
-import android.graphics.Paint
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
+import android.widget.FrameLayout
+import android.widget.ImageView
import androidx.annotation.ColorInt
+import androidx.core.view.isVisible
+import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.util.ViewPool
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
@@ -43,7 +43,7 @@ import com.android.systemui.shared.system.QuickStepContract
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
-class TaskThumbnailView : View, ViewPool.Reusable {
+class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
// TODO(b/335649589): Ideally create and obtain this from DI. This ViewModel should be scoped
// to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
// This is using a lazy for now because the dependencies cannot be obtained without DI.
@@ -59,12 +59,12 @@ class TaskThumbnailView : View, ViewPool.Reusable {
)
}
- private var uiState: TaskThumbnailUiState = Uninitialized
- private var inheritedScale: Float = 1f
- private var dimProgress: Float = 0f
+ private val scrimView: View by lazy { findViewById(R.id.task_thumbnail_scrim) }
+ private val liveTileView: LiveTileView by lazy { findViewById(R.id.task_thumbnail_live_tile) }
+ private val thumbnail: ImageView by lazy { findViewById(R.id.task_thumbnail) }
+
+ private var inheritedScale: Float = 1f
- private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
- private val scrimPaint = Paint().apply { color = Color.BLACK }
private val _measuredBounds = Rect()
private val measuredBounds: Rect
get() {
@@ -75,12 +75,12 @@ class TaskThumbnailView : View, ViewPool.Reusable {
private var overviewCornerRadius: Float = TaskCornerRadius.get(context)
private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
- constructor(context: Context?) : super(context)
+ constructor(context: Context) : super(context)
- constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(
- context: Context?,
+ context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
) : super(context, attrs, defStyleAttr)
@@ -90,15 +90,19 @@ class TaskThumbnailView : View, ViewPool.Reusable {
// TODO(b/335396935) replace MainScope with shorter lifecycle.
MainScope().launch {
viewModel.uiState.collect { viewModelUiState ->
- uiState = viewModelUiState
- invalidate()
+ resetViews()
+ when (viewModelUiState) {
+ is Uninitialized -> {}
+ is LiveTile -> drawLiveWindow()
+ is Snapshot -> drawSnapshot(viewModelUiState)
+ is BackgroundOnly -> drawBackground(viewModelUiState.backgroundColor)
+ }
}
}
MainScope().launch {
viewModel.dimProgress.collect { dimProgress ->
// TODO(b/348195366) Add fade in/out for scrim
- this@TaskThumbnailView.dimProgress = dimProgress
- invalidate()
+ scrimView.alpha = dimProgress * MAX_SCRIM_ALPHA
}
}
MainScope().launch { viewModel.cornerRadiusProgress.collect { invalidateOutline() } }
@@ -120,25 +124,6 @@ class TaskThumbnailView : View, ViewPool.Reusable {
override fun onRecycle() {
// Do nothing
- uiState = Uninitialized
- }
-
- override fun onDraw(canvas: Canvas) {
- when (val uiStateVal = uiState) {
- is Uninitialized -> drawBackgroundOnly(canvas, Color.BLACK)
- is LiveTile -> drawTransparentUiState(canvas)
- is Snapshot -> drawSnapshotState(canvas, uiStateVal)
- is BackgroundOnly -> drawBackgroundOnly(canvas, uiStateVal.backgroundColor)
- }
-
- if (dimProgress > 0) {
- drawScrim(canvas)
- }
- }
-
- private fun drawBackgroundOnly(canvas: Canvas, @ColorInt backgroundColor: Int) {
- backgroundPaint.color = backgroundColor
- canvas.drawRect(measuredBounds, backgroundPaint)
}
override fun onConfigurationChanged(newConfig: Configuration?) {
@@ -149,18 +134,25 @@ class TaskThumbnailView : View, ViewPool.Reusable {
invalidateOutline()
}
- private fun drawTransparentUiState(canvas: Canvas) {
- canvas.drawRect(measuredBounds, CLEAR_PAINT)
+ private fun resetViews() {
+ liveTileView.isVisible = false
+ thumbnail.isVisible = false
+ scrimView.alpha = 0f
+ setBackgroundColor(Color.BLACK)
}
- private fun drawSnapshotState(canvas: Canvas, snapshot: Snapshot) {
- drawBackgroundOnly(canvas, snapshot.backgroundColor)
- canvas.drawBitmap(snapshot.bitmap, snapshot.drawnRect, measuredBounds, null)
+ private fun drawBackground(@ColorInt background: Int) {
+ setBackgroundColor(background)
}
- private fun drawScrim(canvas: Canvas) {
- scrimPaint.alpha = (dimProgress * MAX_SCRIM_ALPHA).toInt()
- canvas.drawRect(measuredBounds, scrimPaint)
+ private fun drawLiveWindow() {
+ liveTileView.isVisible = true
+ }
+
+ private fun drawSnapshot(snapshot: Snapshot) {
+ drawBackground(snapshot.backgroundColor)
+ thumbnail.setImageBitmap(snapshot.bitmap)
+ thumbnail.isVisible = true
}
private fun getCurrentCornerRadius() =
@@ -170,9 +162,7 @@ class TaskThumbnailView : View, ViewPool.Reusable {
fullscreenCornerRadius
) / inheritedScale
- companion object {
- private val CLEAR_PAINT =
- Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
- private const val MAX_SCRIM_ALPHA = (0.4f * 255).toInt()
+ private companion object {
+ const val MAX_SCRIM_ALPHA = 0.4f
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 4333c8b905..9ce2277b14 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -24,6 +24,7 @@ import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.util.AttributeSet
import android.util.Log
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.updateLayoutParams
@@ -36,7 +37,6 @@ import com.android.launcher3.util.ViewPool
import com.android.launcher3.util.rects.set
import com.android.quickstep.BaseContainerInterface
import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.task.thumbnail.TaskThumbnailView
import com.android.quickstep.util.RecentsOrientedState
import com.android.systemui.shared.recents.model.Task
@@ -54,7 +54,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
ViewPool(
context,
this,
- R.layout.task_thumbnail,
+ R.layout.task_thumbnail_deprecated,
VIEW_POOL_MAX_SIZE,
VIEW_POOL_INITIAL_SIZE
)
@@ -108,22 +108,21 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
tasks.map { task ->
val snapshotView =
if (enableRefactorTaskThumbnail()) {
- TaskThumbnailView(context)
- } else {
- taskThumbnailViewDeprecatedPool.view
- }
- .also { snapshotView ->
- addView(
- snapshotView,
- // Add snapshotView to the front after initial views e.g. icon and
- // background.
- childCountAtInflation,
- LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- )
- }
+ LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false)
+ } else {
+ taskThumbnailViewDeprecatedPool.view
+ }
+
+ addView(
+ snapshotView,
+ // Add snapshotView to the front after initial views e.g. icon and
+ // background.
+ childCountAtInflation,
+ LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ )
TaskContainer(
this,
task,
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 4e19d3418c..004003c014 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -31,6 +31,7 @@ import android.util.AttributeSet
import android.util.FloatProperty
import android.util.Log
import android.view.Display
+import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.View.OnClickListener
@@ -666,9 +667,8 @@ constructor(
if (enableRefactorTaskThumbnail()) {
thumbnailViewDeprecated.visibility = GONE
val indexOfSnapshotView = indexOfChild(thumbnailViewDeprecated)
- TaskThumbnailView(context).apply {
- layoutParams = thumbnailViewDeprecated.layoutParams
- addView(this, indexOfSnapshotView)
+ LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false).also {
+ addView(it, indexOfSnapshotView, thumbnailViewDeprecated.layoutParams)
}
} else {
thumbnailViewDeprecated