From 318a65d637bde6cdd240c7d6dcd5d9b4caa75d47 Mon Sep 17 00:00:00 2001 From: Chris Göllner Date: Fri, 5 Apr 2024 11:37:03 +0100 Subject: Partial Screen Sharing: use correct icon badges in recent apps selector We were incorrectly showing the work profile badge for private and cloned apps. Fixes: 314286951 Test: Unit tests in this CL Test: Screenshot test in same topic Flag: NONE Change-Id: I71cdde0574bcfa12478e96e6f79f6d5d0c13161b --- .../MediaProjectionAppSelectorComponent.kt | 6 +- .../appselector/data/AppIconLoader.kt | 61 ---------------- .../appselector/data/BadgedAppIconLoader.kt | 68 ++++++++++++++++++ .../appselector/data/BasicAppIconLoader.kt | 45 ++++++++++++ .../mediaprojection/appselector/data/RecentTask.kt | 10 ++- .../appselector/data/RecentTaskListProvider.kt | 19 ++++- .../appselector/view/RecentTaskViewHolder.kt | 8 +-- .../MediaProjectionAppSelectorControllerTest.kt | 1 + .../data/BasicPackageManagerAppIconLoaderTest.kt | 70 ++++++++++++++++++ .../data/IconLoaderLibAppIconLoaderTest.kt | 83 ---------------------- .../data/ShellRecentTaskListProviderTest.kt | 61 ++++++++++++++-- .../MediaProjectionRecentsViewControllerTest.kt | 3 +- 12 files changed, 273 insertions(+), 162 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt create mode 100644 packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BadgedAppIconLoader.kt create mode 100644 packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BasicAppIconLoader.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index d2471225a093..f08bc17c4f23 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -25,8 +25,8 @@ import com.android.launcher3.icons.IconFactory import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader -import com.android.systemui.mediaprojection.appselector.data.AppIconLoader -import com.android.systemui.mediaprojection.appselector.data.IconLoaderLibAppIconLoader +import com.android.systemui.mediaprojection.appselector.data.BasicAppIconLoader +import com.android.systemui.mediaprojection.appselector.data.BasicPackageManagerAppIconLoader import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader @@ -102,7 +102,7 @@ interface MediaProjectionAppSelectorModule { @Binds @MediaProjectionAppSelectorScope - fun bindAppIconLoader(impl: IconLoaderLibAppIconLoader): AppIconLoader + fun bindAppIconLoader(impl: BasicPackageManagerAppIconLoader): BasicAppIconLoader @Binds @IntoSet diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt deleted file mode 100644 index b85d6285c35b..000000000000 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 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.systemui.mediaprojection.appselector.data - -import android.content.ComponentName -import android.content.Context -import android.content.pm.PackageManager -import android.graphics.drawable.Drawable -import android.os.UserHandle -import com.android.launcher3.icons.BaseIconFactory.IconOptions -import com.android.launcher3.icons.IconFactory -import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.shared.system.PackageManagerWrapper -import javax.inject.Inject -import javax.inject.Provider -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext - -interface AppIconLoader { - suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? -} - -class IconLoaderLibAppIconLoader -@Inject -constructor( - @Background private val backgroundDispatcher: CoroutineDispatcher, - private val context: Context, - // Use wrapper to access hidden API that allows to get ActivityInfo for any user id - private val packageManagerWrapper: PackageManagerWrapper, - private val packageManager: PackageManager, - private val iconFactoryProvider: Provider -) : AppIconLoader { - - override suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? = - withContext(backgroundDispatcher) { - iconFactoryProvider.get().use { iconFactory -> - val activityInfo = - packageManagerWrapper.getActivityInfo(component, userId) - ?: return@withContext null - val icon = activityInfo.loadIcon(packageManager) ?: return@withContext null - val userHandler = UserHandle.of(userId) - val options = IconOptions().apply { setUser(userHandler) } - val badgedIcon = iconFactory.createBadgedIconBitmap(icon, options) - badgedIcon.newIcon(context) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BadgedAppIconLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BadgedAppIconLoader.kt new file mode 100644 index 000000000000..ca5b5f842b25 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BadgedAppIconLoader.kt @@ -0,0 +1,68 @@ +/* + * 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.systemui.mediaprojection.appselector.data + +import android.content.ComponentName +import android.content.Context +import android.graphics.drawable.Drawable +import android.os.UserHandle +import com.android.launcher3.icons.BaseIconFactory +import com.android.launcher3.icons.IconFactory +import com.android.launcher3.util.UserIconInfo +import com.android.systemui.dagger.qualifiers.Background +import javax.inject.Inject +import javax.inject.Provider +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +class BadgedAppIconLoader +@Inject +constructor( + private val basicAppIconLoader: BasicAppIconLoader, + @Background private val backgroundDispatcher: CoroutineDispatcher, + private val context: Context, + private val iconFactoryProvider: Provider, +) { + + suspend fun loadIcon( + userId: Int, + userType: RecentTask.UserType, + componentName: ComponentName + ): Drawable? = + withContext(backgroundDispatcher) { + iconFactoryProvider.get().use { iconFactory -> + val icon = + basicAppIconLoader.loadIcon(userId, componentName) ?: return@withContext null + val userHandler = UserHandle.of(userId) + val iconType = getIconType(userType) + val options = + BaseIconFactory.IconOptions().apply { + setUser(UserIconInfo(userHandler, iconType)) + } + val badgedIcon = iconFactory.createBadgedIconBitmap(icon, options) + badgedIcon.newIcon(context) + } + } + + private fun getIconType(userType: RecentTask.UserType): Int = + when (userType) { + RecentTask.UserType.CLONED -> UserIconInfo.TYPE_CLONED + RecentTask.UserType.WORK -> UserIconInfo.TYPE_WORK + RecentTask.UserType.PRIVATE -> UserIconInfo.TYPE_PRIVATE + RecentTask.UserType.STANDARD -> UserIconInfo.TYPE_MAIN + } +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BasicAppIconLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BasicAppIconLoader.kt new file mode 100644 index 000000000000..03f6f015300f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/BasicAppIconLoader.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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.systemui.mediaprojection.appselector.data + +import android.content.ComponentName +import android.content.pm.PackageManager +import android.graphics.drawable.Drawable +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.shared.system.PackageManagerWrapper +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +interface BasicAppIconLoader { + suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? +} + +class BasicPackageManagerAppIconLoader +@Inject +constructor( + @Background private val backgroundDispatcher: CoroutineDispatcher, + // Use wrapper to access hidden API that allows to get ActivityInfo for any user id + private val packageManagerWrapper: PackageManagerWrapper, + private val packageManager: PackageManager, +) : BasicAppIconLoader { + + override suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? = + withContext(backgroundDispatcher) { + packageManagerWrapper.getActivityInfo(component, userId)?.loadIcon(packageManager) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt index e9b458271ef7..3e9b546d58c9 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt @@ -28,4 +28,12 @@ data class RecentTask( val baseIntentComponent: ComponentName?, @ColorInt val colorBackground: Int?, val isForegroundTask: Boolean, -) + val userType: UserType, +) { + enum class UserType { + STANDARD, + WORK, + PRIVATE, + CLONED + } +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt index 5dde14bf0867..a6049c8b556d 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt @@ -17,6 +17,8 @@ package com.android.systemui.mediaprojection.appselector.data import android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE +import android.content.pm.UserInfo +import android.os.UserManager import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.settings.UserTracker import com.android.systemui.util.kotlin.getOrNull @@ -41,7 +43,8 @@ constructor( @Background private val coroutineDispatcher: CoroutineDispatcher, @Background private val backgroundExecutor: Executor, private val recentTasks: Optional, - private val userTracker: UserTracker + private val userTracker: UserTracker, + private val userManager: UserManager, ) : RecentTaskListProvider { private val recents by lazy { recentTasks.getOrNull() } @@ -65,7 +68,8 @@ constructor( it.topActivity, it.baseIntent?.component, it.taskDescription?.backgroundColor, - isForegroundTask = it.taskId in foregroundTaskIds && it.isVisible + isForegroundTask = it.taskId in foregroundTaskIds && it.isVisible, + userType = userManager.getUserInfo(it.userId).toUserType(), ) } } @@ -81,4 +85,15 @@ constructor( continuation.resume(tasks) } } + + private fun UserInfo.toUserType(): RecentTask.UserType = + if (isCloneProfile) { + RecentTask.UserType.CLONED + } else if (isManagedProfile) { + RecentTask.UserType.WORK + } else if (isPrivateProfile) { + RecentTask.UserType.PRIVATE + } else { + RecentTask.UserType.STANDARD + } } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt index 3fe040a0d715..3b84d2c53a2b 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt @@ -21,12 +21,12 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView.ViewHolder -import com.android.systemui.res.R import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelector -import com.android.systemui.mediaprojection.appselector.data.AppIconLoader +import com.android.systemui.mediaprojection.appselector.data.BadgedAppIconLoader import com.android.systemui.mediaprojection.appselector.data.RecentTask import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader +import com.android.systemui.res.R import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -39,7 +39,7 @@ class RecentTaskViewHolder @AssistedInject constructor( @Assisted private val root: ViewGroup, - private val iconLoader: AppIconLoader, + private val iconLoader: BadgedAppIconLoader, private val thumbnailLoader: RecentTaskThumbnailLoader, private val labelLoader: RecentTaskLabelLoader, private val taskViewSizeProvider: TaskPreviewSizeProvider, @@ -63,7 +63,7 @@ constructor( scope.launch { task.baseIntentComponent?.let { component -> launch { - val icon = iconLoader.loadIcon(task.userId, component) + val icon = iconLoader.loadIcon(task.userId, task.userType, component) iconView.setImageDrawable(icon) } launch { diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt index 44798ea99bee..8b79fa45b8ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt @@ -257,6 +257,7 @@ class MediaProjectionAppSelectorControllerTest : SysuiTestCase() { userId = userId, colorBackground = 0, isForegroundTask = isForegroundTask, + userType = RecentTask.UserType.STANDARD, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt new file mode 100644 index 000000000000..fa1c8f8ea2c7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 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.systemui.mediaprojection.appselector.data + +import android.content.ComponentName +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.graphics.Bitmap +import androidx.test.filters.SmallTest +import com.android.launcher3.icons.FastBitmapDrawable +import com.android.systemui.SysuiTestCase +import com.android.systemui.shared.system.PackageManagerWrapper +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@SmallTest +@RunWith(JUnit4::class) +class BasicPackageManagerAppIconLoaderTest : SysuiTestCase() { + + private val packageManagerWrapper: PackageManagerWrapper = mock() + private val packageManager: PackageManager = mock() + private val dispatcher = Dispatchers.Unconfined + + private val appIconLoader = + BasicPackageManagerAppIconLoader( + backgroundDispatcher = dispatcher, + packageManagerWrapper = packageManagerWrapper, + packageManager = packageManager, + ) + + @Test + fun loadIcon_loadsIconUsingTheSameUserId() { + val icon = createIcon() + val component = ComponentName("com.test", "TestApplication") + givenIcon(component, userId = 123, icon = icon) + + val loadedIcon = runBlocking { appIconLoader.loadIcon(userId = 123, component = component) } + + assertThat(loadedIcon).isEqualTo(icon) + } + + private fun givenIcon(component: ComponentName, userId: Int, icon: FastBitmapDrawable) { + val activityInfo = mock() + whenever(packageManagerWrapper.getActivityInfo(component, userId)).thenReturn(activityInfo) + whenever(activityInfo.loadIcon(packageManager)).thenReturn(icon) + } + + private fun createIcon(): FastBitmapDrawable = + FastBitmapDrawable(Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt deleted file mode 100644 index 9b346d0120ef..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2022 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.systemui.mediaprojection.appselector.data - -import android.content.ComponentName -import android.content.pm.ActivityInfo -import android.content.pm.PackageManager -import android.graphics.Bitmap -import android.graphics.drawable.Drawable -import androidx.test.filters.SmallTest -import com.android.launcher3.icons.BitmapInfo -import com.android.launcher3.icons.FastBitmapDrawable -import com.android.launcher3.icons.IconFactory -import com.android.systemui.SysuiTestCase -import com.android.systemui.shared.system.PackageManagerWrapper -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -@SmallTest -@RunWith(JUnit4::class) -class IconLoaderLibAppIconLoaderTest : SysuiTestCase() { - - private val iconFactory: IconFactory = mock() - private val packageManagerWrapper: PackageManagerWrapper = mock() - private val packageManager: PackageManager = mock() - private val dispatcher = Dispatchers.Unconfined - - private val appIconLoader = - IconLoaderLibAppIconLoader( - backgroundDispatcher = dispatcher, - context = context, - packageManagerWrapper = packageManagerWrapper, - packageManager = packageManager, - iconFactoryProvider = { iconFactory } - ) - - @Test - fun loadIcon_loadsIconUsingTheSameUserId() { - val icon = createIcon() - val component = ComponentName("com.test", "TestApplication") - givenIcon(component, userId = 123, icon = icon) - - val loadedIcon = runBlocking { appIconLoader.loadIcon(userId = 123, component = component) } - - assertThat(loadedIcon).isEqualTo(icon) - } - - private fun givenIcon(component: ComponentName, userId: Int, icon: FastBitmapDrawable) { - val activityInfo = mock() - whenever(packageManagerWrapper.getActivityInfo(component, userId)).thenReturn(activityInfo) - val rawIcon = mock() - whenever(activityInfo.loadIcon(packageManager)).thenReturn(rawIcon) - - val bitmapInfo = mock() - whenever(iconFactory.createBadgedIconBitmap(eq(rawIcon), any())).thenReturn(bitmapInfo) - whenever(bitmapInfo.newIcon(context)).thenReturn(icon) - } - - private fun createIcon(): FastBitmapDrawable = - FastBitmapDrawable(Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)) -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt index b593def283ae..dd621129ad9a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt @@ -1,9 +1,15 @@ package com.android.systemui.mediaprojection.appselector.data import android.app.ActivityManager.RecentTaskInfo +import android.content.pm.UserInfo +import android.os.UserManager import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.mediaprojection.appselector.data.RecentTask.UserType.CLONED +import com.android.systemui.mediaprojection.appselector.data.RecentTask.UserType.PRIVATE +import com.android.systemui.mediaprojection.appselector.data.RecentTask.UserType.STANDARD +import com.android.systemui.mediaprojection.appselector.data.RecentTask.UserType.WORK import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock @@ -17,6 +23,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt @RunWith(AndroidTestingRunner::class) @SmallTest @@ -25,12 +32,16 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { private val dispatcher = Dispatchers.Unconfined private val recentTasks: RecentTasks = mock() private val userTracker: UserTracker = mock() + private val userManager: UserManager = mock { + whenever(getUserInfo(anyInt())).thenReturn(mock()) + } private val recentTaskListProvider = ShellRecentTaskListProvider( dispatcher, Runnable::run, Optional.of(recentTasks), - userTracker + userTracker, + userManager, ) @Test @@ -147,6 +158,22 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { .inOrder() } + @Test + fun loadRecentTasks_assignsCorrectUserType() { + givenRecentTasks( + createSingleTask(taskId = 1, userId = 10, userType = STANDARD), + createSingleTask(taskId = 2, userId = 20, userType = WORK), + createSingleTask(taskId = 3, userId = 30, userType = CLONED), + createSingleTask(taskId = 4, userId = 40, userType = PRIVATE), + ) + + val result = runBlocking { recentTaskListProvider.loadRecentTasks() } + + assertThat(result.map { it.userType }) + .containsExactly(STANDARD, WORK, CLONED, PRIVATE) + .inOrder() + } + @Suppress("UNCHECKED_CAST") private fun givenRecentTasks(vararg tasks: GroupedRecentTaskInfo) { whenever(recentTasks.getRecentTasks(any(), any(), any(), any(), any())).thenAnswer { @@ -155,7 +182,10 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { } } - private fun createRecentTask(taskId: Int): RecentTask = + private fun createRecentTask( + taskId: Int, + userType: RecentTask.UserType = STANDARD + ): RecentTask = RecentTask( taskId = taskId, displayId = 0, @@ -164,25 +194,42 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { baseIntentComponent = null, colorBackground = null, isForegroundTask = false, + userType = userType, ) - private fun createSingleTask(taskId: Int, isVisible: Boolean = false): GroupedRecentTaskInfo = - GroupedRecentTaskInfo.forSingleTask(createTaskInfo(taskId, isVisible)) + private fun createSingleTask( + taskId: Int, + userId: Int = 0, + isVisible: Boolean = false, + userType: RecentTask.UserType = STANDARD, + ): GroupedRecentTaskInfo { + val userInfo = + mock { + whenever(isCloneProfile).thenReturn(userType == CLONED) + whenever(isManagedProfile).thenReturn(userType == WORK) + whenever(isPrivateProfile).thenReturn(userType == PRIVATE) + } + whenever(userManager.getUserInfo(userId)).thenReturn(userInfo) + return GroupedRecentTaskInfo.forSingleTask(createTaskInfo(taskId, userId, isVisible)) + } private fun createTaskPair( taskId1: Int, + userId1: Int = 0, taskId2: Int, + userId2: Int = 0, isVisible: Boolean = false ): GroupedRecentTaskInfo = GroupedRecentTaskInfo.forSplitTasks( - createTaskInfo(taskId1, isVisible), - createTaskInfo(taskId2, isVisible), + createTaskInfo(taskId1, userId1, isVisible), + createTaskInfo(taskId2, userId2, isVisible), null ) - private fun createTaskInfo(taskId: Int, isVisible: Boolean = false) = + private fun createTaskInfo(taskId: Int, userId: Int, isVisible: Boolean = false) = RecentTaskInfo().apply { this.taskId = taskId this.isVisible = isVisible + this.userId = userId } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt index ac4107359dbc..a84008b0353c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt @@ -56,7 +56,8 @@ class MediaProjectionRecentsViewControllerTest : SysuiTestCase() { topActivityComponent = null, baseIntentComponent = null, colorBackground = null, - isForegroundTask = false + isForegroundTask = false, + userType = RecentTask.UserType.STANDARD, ) private val taskView = -- cgit v1.2.3-59-g8ed1b