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

Commit fad73360 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Clean up the routing logic in TopLevelSupervisionPreferenceController" into main

parents e99a1ff3 ecd62678
Loading
Loading
Loading
Loading
+2 −58
Original line number Diff line number Diff line
@@ -19,82 +19,26 @@ import android.app.supervision.flags.Flags
import android.content.Context
import android.content.Intent
import androidx.preference.Preference
import com.android.settings.applications.AppStoreUtil.getAppStoreLink
import com.android.settings.applications.AppStoreUtil.getInstallerPackageName
import com.android.settings.core.BasePreferenceController
import com.android.settings.supervision.ipc.SupervisionMessengerClient.Companion.SUPERVISION_MESSENGER_SERVICE_BIND_ACTION

/** Controller for the top level Supervision settings Preference item. */
class TopLevelSupervisionPreferenceController(context: Context, key: String) :
    BasePreferenceController(context, key) {
    private val supervisionPackage = context.supervisionPackageName

    private var missingAppStoreLink = false

    private var redirectIntent: Intent? = null

    override fun handlePreferenceTreeClick(preference: Preference): Boolean {
        if (preference.key == preferenceKey) {
            val intent =
                redirectIntent ?: Intent(mContext, SupervisionDashboardActivity::class.java)
            val intent = Intent(mContext, SupervisionDashboardActivity::class.java)
            mContext.startActivity(intent)
            return true
        }
        return super.handlePreferenceTreeClick(preference)
    }

    override fun updateState(preference: Preference) {
        super.updateState(preference)
        if (!hasNecessarySupervisionComponent() && missingAppStoreLink) {
            preference.isEnabled = false
        }
    }

    override fun getAvailabilityStatus(): Int {
        if (!Flags.enableSupervisionSettingsScreen() || supervisionPackage == null)
        if (!Flags.enableSupervisionSettingsScreen()) {
            return UNSUPPORTED_ON_DEVICE

        // Try to navigate to app store if supervision app with necessary component is not installed
        if (!hasNecessarySupervisionComponent()) {
            val installerPackageName = getInstallerPackageName(mContext, supervisionPackage)
            val appStoreLinkIntent =
                installerPackageName?.let {
                    getAppStoreLink(mContext, installerPackageName, supervisionPackage)
                }
            if (appStoreLinkIntent == null) {
                missingAppStoreLink = true
                return AVAILABLE
            }
            missingAppStoreLink = false
            redirectIntent = appStoreLinkIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }

        if (hasRedirect()) {
            redirectIntent = Intent(SETTINGS_REDIRECT_ACTION).setPackage(supervisionPackage)
        }

        return AVAILABLE
    }

    private fun hasNecessarySupervisionComponent(): Boolean {
        val intent =
            Intent(SUPERVISION_MESSENGER_SERVICE_BIND_ACTION).setPackage(supervisionPackage)

        return supervisionPackage != null &&
            mContext.packageManager.queryIntentServices(intent, 0).isNotEmpty()
    }

    private fun hasRedirect(): Boolean {
        val intent = Intent(SETTINGS_REDIRECT_ACTION).setPackage(supervisionPackage)
        return supervisionPackage != null &&
            mContext.packageManager
                .queryIntentActivitiesAsUser(intent, 0, mContext.userId)
                .isNotEmpty()
    }

    companion object {
        // Supervision app should declare an intent-filter with this action to redirect the settings
        // navigation target.
        const val SETTINGS_REDIRECT_ACTION = "android.app.supervision.action.VIEW_SETTINGS"
    }
}
+2 −123
Original line number Diff line number Diff line
@@ -16,39 +16,23 @@
package com.android.settings.supervision

import android.app.Activity
import android.app.role.RoleManager
import android.content.Context
import android.content.Intent
import android.content.pm.InstallSourceInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import androidx.preference.Preference
import com.android.settings.core.BasePreferenceController.AVAILABLE
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
import com.android.settings.supervision.TopLevelSupervisionPreferenceController.Companion.SETTINGS_REDIRECT_ACTION
import com.android.settings.supervision.ipc.SupervisionMessengerClient.Companion.SUPERVISION_MESSENGER_SERVICE_BIND_ACTION
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.argThat
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub
import org.mockito.kotlin.verify
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class TopLevelSupervisionPreferenceControllerTest {
    private val mockRoleManager = mock<RoleManager>()
    private val mockPackageManager = mock<PackageManager>()
    private val context =
        spy(Robolectric.buildActivity(Activity::class.java).get()) {
            on { getSystemService(Context.ROLE_SERVICE) }.thenReturn(mockRoleManager)
            on { packageManager }.thenReturn(mockPackageManager)
        }
        spy(Robolectric.buildActivity(Activity::class.java).get())

    private val preference = Preference(context)

@@ -58,109 +42,7 @@ class TopLevelSupervisionPreferenceControllerTest {
    }

    @Test
    fun supervisionPackageNameIsNull_returnUnsupported() {
        mockRoleManager.stub {
            on { getRoleHolders(RoleManager.ROLE_SYSTEM_SUPERVISION) }.thenReturn(listOf<String>())
        }

        val preferenceController = TopLevelSupervisionPreferenceController(context, PREFERENCE_KEY)
        verify(mockRoleManager).getRoleHolders(any())
        assertThat(preferenceController.availabilityStatus).isEqualTo(UNSUPPORTED_ON_DEVICE)
    }

    @Test
    fun noNecessaryComponent_noAppStoreLink_preferenceDisabled() {
        mockRoleManager.stub {
            on { getRoleHolders(RoleManager.ROLE_SYSTEM_SUPERVISION) }
                .thenReturn(listOf(SUPERVISION_PACKAGE_NAME))
        }

        mockPackageManager.stub {
            on {
                    queryIntentServices(
                        actionIntentMatcher(SUPERVISION_MESSENGER_SERVICE_BIND_ACTION),
                        any<Int>(),
                    )
                }
                .thenReturn(listOf())
        }
        mockPackageManager.stub {
            on { getInstallSourceInfo(any()) }.thenReturn(InstallSourceInfo(null, null, null, null))
        }

        val preferenceController = TopLevelSupervisionPreferenceController(context, PREFERENCE_KEY)

        assertThat(preferenceController.availabilityStatus).isEqualTo(AVAILABLE)
        preferenceController.handlePreferenceTreeClick(preference)
        preferenceController.updateState(preference)

        assertThat(preference.isEnabled).isFalse()
        verify(context)
            .startActivity(componentIntentMatcher(SupervisionDashboardActivity::class.java))
    }

    @Test
    fun hasNecessaryComponent_isFullySupervised_launchFullSupervision() {
        mockRoleManager.stub {
            on { getRoleHolders(RoleManager.ROLE_SYSTEM_SUPERVISION) }
                .thenReturn(listOf(SUPERVISION_PACKAGE_NAME))
        }

        mockPackageManager.stub {
            on {
                    queryIntentServices(
                        actionIntentMatcher(SUPERVISION_MESSENGER_SERVICE_BIND_ACTION),
                        any<Int>(),
                    )
                }
                .thenReturn(listOf(ResolveInfo()))
        }
        mockPackageManager.stub {
            on {
                    queryIntentActivitiesAsUser(
                        actionIntentMatcher(SETTINGS_REDIRECT_ACTION),
                        any<Int>(),
                        any<Int>(),
                    )
                }
                .thenReturn(listOf(ResolveInfo()))
        }

        val preferenceController = TopLevelSupervisionPreferenceController(context, PREFERENCE_KEY)

        assertThat(preferenceController.availabilityStatus).isEqualTo(AVAILABLE)
        preferenceController.handlePreferenceTreeClick(preference)

        verify(context).startActivity(actionIntentMatcher(SETTINGS_REDIRECT_ACTION))
    }

    @Test
    fun hasNecessaryComponent_isNotFullySupervised_returnAvailable() {
        mockRoleManager.stub {
            on { getRoleHolders(RoleManager.ROLE_SYSTEM_SUPERVISION) }
                .thenReturn(listOf(SUPERVISION_PACKAGE_NAME))
        }

        mockPackageManager.stub {
            on {
                    queryIntentServices(
                        actionIntentMatcher(SUPERVISION_MESSENGER_SERVICE_BIND_ACTION),
                        any<Int>(),
                    )
                }
                .thenReturn(listOf(ResolveInfo()))
        }
        mockPackageManager.stub {
            on {
                    queryIntentActivitiesAsUser(
                        actionIntentMatcher(SETTINGS_REDIRECT_ACTION),
                        any<Int>(),
                        any<Int>(),
                    )
                }
                .thenReturn(listOf())
        }

    fun navigateToDashboard() {
        val preferenceController = TopLevelSupervisionPreferenceController(context, PREFERENCE_KEY)

        assertThat(preferenceController.availabilityStatus).isEqualTo(AVAILABLE)
@@ -170,13 +52,10 @@ class TopLevelSupervisionPreferenceControllerTest {
            .startActivity(componentIntentMatcher(SupervisionDashboardActivity::class.java))
    }

    private fun actionIntentMatcher(action: String) = argThat<Intent> { this.action == action }

    private fun componentIntentMatcher(cls: Class<*>) =
        argThat<Intent> { this.component?.className == cls.name }

    private companion object {
        const val SUPERVISION_PACKAGE_NAME = "com.android.supervision"
        const val PREFERENCE_KEY = "test_key"
    }
}