Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b4deb11 authored by Zhou Liu's avatar Zhou Liu
Browse files

[Device Supervision] Dynamically set preference metadata of SupervisionPromoFooterPreference

Test: atest SupervisionPromoFooterPreferenceTest
Bug: 399497788
Flag: android.app.supervision.flags.enable_supervision_settings_screen
Change-Id: Id9f8105440e973f77b7725371e7bdafd66df37ae
parent eff614f8
Loading
Loading
Loading
Loading
+44 −27
Original line number Diff line number Diff line
@@ -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
@@ -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)
        }
    }
+73 −20
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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>()) }