Loading src/com/android/settings/supervision/SupervisionPromoFooterPreference.kt +44 −27 Original line number Diff line number Diff line Loading @@ -17,12 +17,12 @@ package com.android.settings.supervision import android.content.Context import android.content.Intent import android.graphics.drawable.Icon import androidx.preference.Preference import com.android.settings.supervision.ipc.PreferenceData import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.PreferenceLifecycleProvider import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceSummaryProvider import com.android.settingslib.metadata.PreferenceTitleProvider import com.android.settingslib.preference.PreferenceBinding import com.android.settingslib.widget.CardPreference import kotlinx.coroutines.CoroutineDispatcher Loading @@ -34,53 +34,70 @@ import kotlinx.coroutines.withContext class SupervisionPromoFooterPreference( private val preferenceDataProvider: PreferenceDataProvider, private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : PreferenceMetadata, PreferenceBinding, PreferenceLifecycleProvider, PreferenceTitleProvider, PreferenceSummaryProvider { ) : PreferenceMetadata, PreferenceBinding, PreferenceLifecycleProvider { /** Whether [intent] holds an initialized value. */ /** Whether [preferenceData] holds an initialized value. */ private var initialized = false // Operation to be performed when the preference is clicked private var intent: Intent? = null private var preferenceData: PreferenceData? = null override val key: String get() = KEY // TODO(b/399497788): Remove this and get title from supervision app override fun getTitle(context: Context) = "Full parental controls" // TODO(b/399497788): Remove this and get summary from supervision app override fun getSummary(context: Context) = "Set up an account for your kid & help them manage it (required for kids under [AOC])" override fun createWidget(context: Context) = CardPreference(context) override fun bind(preference: Preference, metadata: PreferenceMetadata) { super.bind(preference, metadata) var intent: Intent? = null if (initialized) { val targetIntent = Intent(preferenceData?.action).apply { `package` = preferenceData?.targetPackage addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } intent = if (targetIntent.isValid(preference.context)) targetIntent else null val leadingIconResId = preferenceData?.icon val leadingIcon = leadingIconResId?.let { val resourcePackage = SupervisionHelper.getInstance(preference.context) .getSupervisionPackageName() val icon = Icon.createWithResource(resourcePackage, leadingIconResId) icon.loadDrawable(preference.context) } preference.intent = intent preference.isVisible = intent != null preference.title = preferenceData?.title ?: preference.title preference.summary = preferenceData?.summary ?: preference.summary preference.icon = leadingIcon ?: preference.icon val trailingIcon: Int? = preferenceData?.trailingIcon if (trailingIcon != null) { (preference as CardPreference).setAdditionalAction( trailingIcon, // TODO(b/411279121): add content description once we have the finalized string. contentDescription = "", ) { it.performClick() } } } // Icon, Title, Summary may be null but at least one of title or summary must be valid // and the action has to be valid for the preference to be visible. preference.isVisible = intent != null && (preferenceData?.title != null || preferenceData?.summary != null) } override fun onResume(context: PreferenceLifecycleContext) { context.lifecycleScope.launch { // TODO(b/399497788) Get title & summary from supervision app. val preferenceData = preferenceData = withContext(coroutineDispatcher) { preferenceDataProvider.getPreferenceData(listOf(KEY))[KEY] } initialized = true val targetIntent = Intent(preferenceData?.action).apply { `package` = preferenceData?.targetPackage addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } if (targetIntent.isValid(context)) intent = targetIntent context.notifyPreferenceChange(KEY) } } Loading tests/robotests/src/com/android/settings/supervision/SupervisionPromoFooterPreferenceTest.kt +73 −20 Original line number Diff line number Diff line Loading @@ -15,7 +15,9 @@ */ package com.android.settings.supervision import android.app.role.RoleManager import android.content.Context import android.content.ContextWrapper import android.content.pm.PackageManager import android.content.pm.ResolveInfo import androidx.preference.Preference Loading @@ -24,17 +26,17 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.supervision.SupervisionPromoFooterPreference.Companion.KEY import com.android.settings.supervision.ipc.PreferenceData import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.getPreferenceSummary import com.android.settingslib.metadata.getPreferenceTitle import com.android.settingslib.widget.CardPreference import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.stub Loading @@ -43,7 +45,21 @@ import org.mockito.kotlin.verify @ExperimentalCoroutinesApi @RunWith(AndroidJUnit4::class) class SupervisionPromoFooterPreferenceTest { private val context: Context = ApplicationProvider.getApplicationContext() private val mockPackageManager: PackageManager = mock() private val context: Context = object : ContextWrapper(ApplicationProvider.getApplicationContext()) { override fun getSystemService(name: String): Any? = when (name) { ROLE_SERVICE -> mockRoleManager else -> super.getSystemService(name) } override fun getPackageManager(): PackageManager { return mockPackageManager } } private val mockRoleManager = mock<RoleManager> { on { getRoleHolders(any()) } doReturn listOf("test.package") } private val preference = CardPreference(context) private var preferenceData: PreferenceData? = null Loading @@ -51,7 +67,6 @@ class SupervisionPromoFooterPreferenceTest { private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) private val mockPackageManager: PackageManager = mock() private val preferenceLifecycleContext: PreferenceLifecycleContext = mock { on { lifecycleScope }.thenReturn(testScope) on { packageManager }.thenReturn(mockPackageManager) Loading @@ -67,23 +82,56 @@ class SupervisionPromoFooterPreferenceTest { } } @Before fun setUp() { SupervisionHelper.sInstance = null } @Test fun getTitle_returnsCorrectTitle() { val supervisionPromoFooterPreference = SupervisionPromoFooterPreference(preferenceDataProvider) assertThat(supervisionPromoFooterPreference.getPreferenceTitle(context)) .isEqualTo("Full parental controls") fun onResume_setTitle() = testScope.runTest { val title = "test title" preferenceData = PreferenceData(title = title) val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) promoPreference.onResume(preferenceLifecycleContext) verify(preferenceLifecycleContext).notifyPreferenceChange(KEY) promoPreference.bind(preference, mock()) assertThat(preference.title).isEqualTo(title) } @Test fun getSummary_returnsCorrectSummary() { val supervisionPromoFooterPreference = SupervisionPromoFooterPreference(preferenceDataProvider) assertThat(supervisionPromoFooterPreference.getPreferenceSummary(context)) .isEqualTo( "Set up an account for your kid & help them manage it (required for " + "kids under [AOC])" ) fun onResume_setSummary() = testScope.runTest { val summary = "test summary" preferenceData = PreferenceData(summary = summary) val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) promoPreference.onResume(preferenceLifecycleContext) verify(preferenceLifecycleContext).notifyPreferenceChange(KEY) promoPreference.bind(preference, mock()) assertThat(preference.summary).isEqualTo(summary) } @Test fun onResume_loadingIconSetFromSupervisionPackage() = testScope.runTest { preferenceData = PreferenceData(icon = 123) SupervisionHelper.sInstance = SupervisionHelper.getInstance(context) val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) promoPreference.onResume(preferenceLifecycleContext) verify(preferenceLifecycleContext).notifyPreferenceChange(KEY) promoPreference.bind(preference, mock()) verify(mockRoleManager).getRoleHolders(RoleManager.ROLE_SYSTEM_SUPERVISION) } @Test Loading Loading @@ -162,7 +210,12 @@ class SupervisionPromoFooterPreferenceTest { testScope.runTest { val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) preferenceData = PreferenceData(action = "Test Action", targetPackage = "test.package") preferenceData = PreferenceData( title = "Test Title", action = "Test Action", targetPackage = "test.package", ) mockPackageManager.stub { on { queryIntentActivitiesAsUser(any(), any<Int>(), any<Int>()) } Loading Loading
src/com/android/settings/supervision/SupervisionPromoFooterPreference.kt +44 −27 Original line number Diff line number Diff line Loading @@ -17,12 +17,12 @@ package com.android.settings.supervision import android.content.Context import android.content.Intent import android.graphics.drawable.Icon import androidx.preference.Preference import com.android.settings.supervision.ipc.PreferenceData import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.PreferenceLifecycleProvider import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceSummaryProvider import com.android.settingslib.metadata.PreferenceTitleProvider import com.android.settingslib.preference.PreferenceBinding import com.android.settingslib.widget.CardPreference import kotlinx.coroutines.CoroutineDispatcher Loading @@ -34,53 +34,70 @@ import kotlinx.coroutines.withContext class SupervisionPromoFooterPreference( private val preferenceDataProvider: PreferenceDataProvider, private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : PreferenceMetadata, PreferenceBinding, PreferenceLifecycleProvider, PreferenceTitleProvider, PreferenceSummaryProvider { ) : PreferenceMetadata, PreferenceBinding, PreferenceLifecycleProvider { /** Whether [intent] holds an initialized value. */ /** Whether [preferenceData] holds an initialized value. */ private var initialized = false // Operation to be performed when the preference is clicked private var intent: Intent? = null private var preferenceData: PreferenceData? = null override val key: String get() = KEY // TODO(b/399497788): Remove this and get title from supervision app override fun getTitle(context: Context) = "Full parental controls" // TODO(b/399497788): Remove this and get summary from supervision app override fun getSummary(context: Context) = "Set up an account for your kid & help them manage it (required for kids under [AOC])" override fun createWidget(context: Context) = CardPreference(context) override fun bind(preference: Preference, metadata: PreferenceMetadata) { super.bind(preference, metadata) var intent: Intent? = null if (initialized) { val targetIntent = Intent(preferenceData?.action).apply { `package` = preferenceData?.targetPackage addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } intent = if (targetIntent.isValid(preference.context)) targetIntent else null val leadingIconResId = preferenceData?.icon val leadingIcon = leadingIconResId?.let { val resourcePackage = SupervisionHelper.getInstance(preference.context) .getSupervisionPackageName() val icon = Icon.createWithResource(resourcePackage, leadingIconResId) icon.loadDrawable(preference.context) } preference.intent = intent preference.isVisible = intent != null preference.title = preferenceData?.title ?: preference.title preference.summary = preferenceData?.summary ?: preference.summary preference.icon = leadingIcon ?: preference.icon val trailingIcon: Int? = preferenceData?.trailingIcon if (trailingIcon != null) { (preference as CardPreference).setAdditionalAction( trailingIcon, // TODO(b/411279121): add content description once we have the finalized string. contentDescription = "", ) { it.performClick() } } } // Icon, Title, Summary may be null but at least one of title or summary must be valid // and the action has to be valid for the preference to be visible. preference.isVisible = intent != null && (preferenceData?.title != null || preferenceData?.summary != null) } override fun onResume(context: PreferenceLifecycleContext) { context.lifecycleScope.launch { // TODO(b/399497788) Get title & summary from supervision app. val preferenceData = preferenceData = withContext(coroutineDispatcher) { preferenceDataProvider.getPreferenceData(listOf(KEY))[KEY] } initialized = true val targetIntent = Intent(preferenceData?.action).apply { `package` = preferenceData?.targetPackage addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } if (targetIntent.isValid(context)) intent = targetIntent context.notifyPreferenceChange(KEY) } } Loading
tests/robotests/src/com/android/settings/supervision/SupervisionPromoFooterPreferenceTest.kt +73 −20 Original line number Diff line number Diff line Loading @@ -15,7 +15,9 @@ */ package com.android.settings.supervision import android.app.role.RoleManager import android.content.Context import android.content.ContextWrapper import android.content.pm.PackageManager import android.content.pm.ResolveInfo import androidx.preference.Preference Loading @@ -24,17 +26,17 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.supervision.SupervisionPromoFooterPreference.Companion.KEY import com.android.settings.supervision.ipc.PreferenceData import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.getPreferenceSummary import com.android.settingslib.metadata.getPreferenceTitle import com.android.settingslib.widget.CardPreference import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.stub Loading @@ -43,7 +45,21 @@ import org.mockito.kotlin.verify @ExperimentalCoroutinesApi @RunWith(AndroidJUnit4::class) class SupervisionPromoFooterPreferenceTest { private val context: Context = ApplicationProvider.getApplicationContext() private val mockPackageManager: PackageManager = mock() private val context: Context = object : ContextWrapper(ApplicationProvider.getApplicationContext()) { override fun getSystemService(name: String): Any? = when (name) { ROLE_SERVICE -> mockRoleManager else -> super.getSystemService(name) } override fun getPackageManager(): PackageManager { return mockPackageManager } } private val mockRoleManager = mock<RoleManager> { on { getRoleHolders(any()) } doReturn listOf("test.package") } private val preference = CardPreference(context) private var preferenceData: PreferenceData? = null Loading @@ -51,7 +67,6 @@ class SupervisionPromoFooterPreferenceTest { private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) private val mockPackageManager: PackageManager = mock() private val preferenceLifecycleContext: PreferenceLifecycleContext = mock { on { lifecycleScope }.thenReturn(testScope) on { packageManager }.thenReturn(mockPackageManager) Loading @@ -67,23 +82,56 @@ class SupervisionPromoFooterPreferenceTest { } } @Before fun setUp() { SupervisionHelper.sInstance = null } @Test fun getTitle_returnsCorrectTitle() { val supervisionPromoFooterPreference = SupervisionPromoFooterPreference(preferenceDataProvider) assertThat(supervisionPromoFooterPreference.getPreferenceTitle(context)) .isEqualTo("Full parental controls") fun onResume_setTitle() = testScope.runTest { val title = "test title" preferenceData = PreferenceData(title = title) val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) promoPreference.onResume(preferenceLifecycleContext) verify(preferenceLifecycleContext).notifyPreferenceChange(KEY) promoPreference.bind(preference, mock()) assertThat(preference.title).isEqualTo(title) } @Test fun getSummary_returnsCorrectSummary() { val supervisionPromoFooterPreference = SupervisionPromoFooterPreference(preferenceDataProvider) assertThat(supervisionPromoFooterPreference.getPreferenceSummary(context)) .isEqualTo( "Set up an account for your kid & help them manage it (required for " + "kids under [AOC])" ) fun onResume_setSummary() = testScope.runTest { val summary = "test summary" preferenceData = PreferenceData(summary = summary) val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) promoPreference.onResume(preferenceLifecycleContext) verify(preferenceLifecycleContext).notifyPreferenceChange(KEY) promoPreference.bind(preference, mock()) assertThat(preference.summary).isEqualTo(summary) } @Test fun onResume_loadingIconSetFromSupervisionPackage() = testScope.runTest { preferenceData = PreferenceData(icon = 123) SupervisionHelper.sInstance = SupervisionHelper.getInstance(context) val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) promoPreference.onResume(preferenceLifecycleContext) verify(preferenceLifecycleContext).notifyPreferenceChange(KEY) promoPreference.bind(preference, mock()) verify(mockRoleManager).getRoleHolders(RoleManager.ROLE_SYSTEM_SUPERVISION) } @Test Loading Loading @@ -162,7 +210,12 @@ class SupervisionPromoFooterPreferenceTest { testScope.runTest { val promoPreference = SupervisionPromoFooterPreference(preferenceDataProvider, testDispatcher) preferenceData = PreferenceData(action = "Test Action", targetPackage = "test.package") preferenceData = PreferenceData( title = "Test Title", action = "Test Action", targetPackage = "test.package", ) mockPackageManager.stub { on { queryIntentActivitiesAsUser(any(), any<Int>(), any<Int>()) } Loading