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

Commit e7c396dc authored by Sandy Pan's avatar Sandy Pan
Browse files

Reset the supervising user when pin recovery

occurs. This is the short-term solution based on
go/kf-ramen-pin-recovery.

Test: SupervisionPinRecoveryActivityTest.kt
Bug: 411682292
Flag: android.app.supervision.flags.enable_supervision_pin_recovery_screen
Change-Id: I23756ef41d9004a5ce5d6271431388066b3fff39
parent 9a7259d7
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -121,7 +121,12 @@ class SupervisionMainSwitchPreference(
        }
        if (resultCode == Activity.RESULT_OK) {
            val mainSwitchPreference = lifeCycleContext.requirePreference<MainSwitchPreference>(KEY)
            val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!!
            val newValue =
                if (requestCode == REQUEST_CODE_SET_UP_SUPERVISION) {
                    true
                } else {
                    !supervisionMainSwitchStorage.getBoolean(KEY)!!
                }
            mainSwitchPreference.setChecked(newValue)
            updateDependentPreferencesEnabledState(mainSwitchPreference, newValue)
            updateDependentPreferenceSummary(mainSwitchPreference)
+43 −7
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.settings.supervision

import android.Manifest
import android.app.Activity
import android.app.supervision.SupervisionManager
import android.app.supervision.SupervisionRecoveryInfo
@@ -23,13 +24,16 @@ import android.app.supervision.SupervisionRecoveryInfo.STATE_VERIFIED
import android.content.Intent
import android.os.Bundle
import android.os.PersistableBundle
import android.os.UserManager
import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresPermission
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.FragmentActivity
import com.android.settings.R
import com.android.settings.password.ChooseLockPassword
import com.android.settingslib.supervision.SupervisionIntentProvider
import com.android.settingslib.supervision.SupervisionLog

@@ -163,10 +167,10 @@ class SupervisionPinRecoveryActivity : FragmentActivity() {
    }

    private fun onVerification(resultCode: Int, data: Intent?) {
        if (resultCode == Activity.RESULT_OK) {
        if (resultCode == RESULT_OK) {
            val action = intent.action
            when (action) {
                ACTION_RECOVERY -> startResetPinActivity() // Continue to set PIN after verification
                ACTION_RECOVERY -> startResetPinActivity() // reset PIN after verification
                ACTION_SETUP,
                ACTION_UPDATE,
                ACTION_SETUP_VERIFIED,
@@ -219,9 +223,15 @@ class SupervisionPinRecoveryActivity : FragmentActivity() {
    }

    /** Starts the reset supervision PIN activity for the supervising user. */
    @RequiresPermission(
        anyOf = [Manifest.permission.CREATE_USERS, Manifest.permission.MANAGE_USERS]
    )
    private fun startResetPinActivity() {
        // TODO(b/407064075): reset the user or use other activity to skip entering current PIN.
        val intent = Intent(this, ChooseLockPassword::class.java)
        if (!resetSupervisionUser()) {
            handleError("Failed to reset supervision user.")
            return
        }
        val intent = Intent(this, SupervisionCredentialProxyActivity::class.java)
        setPinLauncher.launch(intent)
    }

@@ -238,6 +248,32 @@ class SupervisionPinRecoveryActivity : FragmentActivity() {
        finish()
    }

    /**
     * Resets the supervision user by removing the existing one and creating a new one.
     *
     * This method first retrieves the current supervising user handle. If it exists, the user is
     * removed. Then, a new supervising user is created.
     *
     * @return True if the reset was successful, false otherwise.
     *
     * TODO(b/407064075): use better approach to reset the supervision user.
     */
    @RequiresPermission(
        anyOf = [Manifest.permission.CREATE_USERS, Manifest.permission.MANAGE_USERS]
    )
    private fun resetSupervisionUser(): Boolean {
        val userManager = getSystemService(UserManager::class.java)
        supervisingUserHandle?.let { userManager.removeUser(it) }
        val userInfo =
            userManager.createUser("Supervising", USER_TYPE_PROFILE_SUPERVISING, /* flags= */ 0)
        if (userInfo != null) {
            return true
        } else {
            Log.e(SupervisionLog.TAG, "Unable to create supervising profile.")
            return false
        }
    }

    companion object {
        // Action types for the PIN recovery activity.
        const val ACTION_SETUP = "android.app.supervision.action.SETUP_PIN_RECOVERY"
@@ -249,7 +285,7 @@ class SupervisionPinRecoveryActivity : FragmentActivity() {
            "android.app.supervision.action.POST_SETUP_VERIFY_PIN_RECOVERY"

        // Extra keys
        private const val EXTRA_RECOVERY_EMAIL = "recoveryEmail"
        private const val EXTRA_RECOVERY_ID = "recoveryId"
        @VisibleForTesting const val EXTRA_RECOVERY_EMAIL = "recoveryEmail"
        @VisibleForTesting const val EXTRA_RECOVERY_ID = "recoveryId"
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import org.robolectric.shadows.ShadowPackageManager
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.BAKLAVA])
class SupervisionPinRecoveryActivityTest {
    // TODO(b/399484695): Add test cases to verify different scenarios.
    // TODO(b/414457269): Add test cases to verify different scenarios.

    private lateinit var activity: SupervisionPinRecoveryActivity
    private val context: Context = ApplicationProvider.getApplicationContext()