diff options
| author | 2023-02-27 07:24:49 +0000 | |
|---|---|---|
| committer | 2023-02-27 07:24:49 +0000 | |
| commit | 268ad5716f7e0ac4a98a4420e52f47c8e2de0cba (patch) | |
| tree | 6e9311a080e5a2ed0243bd1baa53b8a645b28ce6 | |
| parent | 745ed44e0b252d8e39adc9efcca0cb495a8873a4 (diff) | |
| parent | 0c646645c5b37ffcdc58477f6b8fc60cffa65804 (diff) | |
Merge "Add work profile content description for app" into udc-dev
4 files changed, 127 insertions, 10 deletions
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt index 18b207337ad4..1a7d8968f232 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt @@ -19,7 +19,6 @@ package com.android.settingslib.spaprivileged.model.app import android.content.Context import android.content.pm.ApplicationInfo import android.graphics.drawable.Drawable -import android.os.UserManager import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState @@ -28,6 +27,7 @@ import androidx.compose.ui.res.stringResource import com.android.settingslib.Utils import com.android.settingslib.spa.framework.compose.rememberContext import com.android.settingslib.spaprivileged.R +import com.android.settingslib.spaprivileged.framework.common.userManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -42,23 +42,25 @@ interface AppRepository { val context = LocalContext.current return produceState(initialValue = stringResource(R.string.summary_placeholder), app) { withContext(Dispatchers.IO) { - if (isClonedAppPage || isCloneApp(context, app)) { - value = context.getString(R.string.cloned_app_info_label, loadLabel(app)) + value = if (isClonedAppPage || isCloneApp(context, app)) { + context.getString(R.string.cloned_app_info_label, loadLabel(app)) } else { - value = loadLabel(app) + loadLabel(app) } } } } private fun isCloneApp(context: Context, app: ApplicationInfo): Boolean { - val userManager = context.getSystemService(UserManager::class.java)!! - val userInfo = userManager.getUserInfo(app.userId) + val userInfo = context.userManager.getUserInfo(app.userId) return userInfo != null && userInfo.isCloneProfile } @Composable fun produceIcon(app: ApplicationInfo): State<Drawable?> + + @Composable + fun produceIconContentDescription(app: ApplicationInfo): State<String?> } internal class AppRepositoryImpl(private val context: Context) : AppRepository { @@ -69,8 +71,22 @@ internal class AppRepositoryImpl(private val context: Context) : AppRepository { @Composable override fun produceIcon(app: ApplicationInfo) = produceState<Drawable?>(initialValue = null, app) { - withContext(Dispatchers.Default) { + withContext(Dispatchers.IO) { value = Utils.getBadgedIcon(context, app) } } + + @Composable + override fun produceIconContentDescription(app: ApplicationInfo) = + produceState<String?>(initialValue = null, app) { + withContext(Dispatchers.IO) { + value = when { + context.userManager.isManagedProfile(app.userId) -> { + context.getString(R.string.category_work) + } + + else -> null + } + } + } } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt index 602df54ed3fb..e3ea2e78756f 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.compose.rememberDrawablePainter @@ -50,7 +51,8 @@ class AppInfoProvider(private val packageInfo: PackageInfo) { .padding( horizontal = SettingsDimension.itemPaddingStart, vertical = SettingsDimension.itemPaddingVertical, - ), + ) + .semantics(mergeDescendants = true) {}, horizontalAlignment = Alignment.CenterHorizontally, ) { val app = packageInfo.applicationInfo @@ -93,8 +95,8 @@ internal fun AppIcon(app: ApplicationInfo, size: Dp) { val appRepository = rememberAppRepository() Image( painter = rememberDrawablePainter(appRepository.produceIcon(app).value), - contentDescription = null, - modifier = Modifier.size(size) + contentDescription = appRepository.produceIconContentDescription(app).value, + modifier = Modifier.size(size), ) } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt index fc40aed43c92..4f0cddef078b 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt @@ -103,6 +103,9 @@ class AppListViewModelTest { @Composable override fun produceIcon(app: ApplicationInfo) = stateOf(null) + + @Composable + override fun produceIconContentDescription(app: ApplicationInfo) = stateOf(null) } private companion object { diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt new file mode 100644 index 000000000000..26caa01192c5 --- /dev/null +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 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.settingslib.spaprivileged.model.app + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.os.UserManager +import androidx.compose.runtime.State +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.framework.compose.stateOf +import com.android.settingslib.spa.testutils.delay +import com.android.settingslib.spaprivileged.R +import com.android.settingslib.spaprivileged.framework.common.userManager +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Spy +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.Mockito.`when` as whenever + +@RunWith(AndroidJUnit4::class) +class AppRepositoryTest { + @get:Rule + val composeTestRule = createComposeRule() + + @get:Rule + val mockito: MockitoRule = MockitoJUnit.rule() + + @Spy + private val context: Context = ApplicationProvider.getApplicationContext() + + @Mock + private lateinit var userManager: UserManager + + private lateinit var appRepository: AppRepositoryImpl + + @Before + fun setUp() { + whenever(context.userManager).thenReturn(userManager) + appRepository = AppRepositoryImpl(context) + } + + @Test + fun produceIconContentDescription_workProfile() { + whenever(userManager.isManagedProfile(APP.userId)).thenReturn(true) + + val contentDescription = produceIconContentDescription() + + assertThat(contentDescription.value).isEqualTo(context.getString(R.string.category_work)) + } + + @Test + fun produceIconContentDescription_personalProfile() { + whenever(userManager.isManagedProfile(APP.userId)).thenReturn(false) + + val contentDescription = produceIconContentDescription() + + assertThat(contentDescription.value).isNull() + } + + private fun produceIconContentDescription(): State<String?> { + var contentDescription: State<String?> = stateOf(null) + composeTestRule.setContent { + contentDescription = appRepository.produceIconContentDescription(APP) + } + composeTestRule.delay() + return contentDescription + } + + private companion object { + const val UID = 123 + val APP = ApplicationInfo().apply { + uid = UID + } + } +}
\ No newline at end of file |