[Device Supervision] Implement createConfirmSupervisionCredentialsIntent API
The `ConfirmSupervisionCredentialsActivity` has been added and it's intended to be launched via the intent. Bug: 392961554 Flag: android.app.supervision.flags.enable_supervision_settings_screen Test: atest SupervisionMainSwitchPreferenceTest Change-Id: I2322256a5711d5b90f826f467110c6861a7734ad
This commit is contained in:
@@ -139,6 +139,7 @@ android_library {
|
|||||||
"aconfig_settings_flags",
|
"aconfig_settings_flags",
|
||||||
"aconfig_settingslib_flags",
|
"aconfig_settingslib_flags",
|
||||||
"android.app.flags-aconfig",
|
"android.app.flags-aconfig",
|
||||||
|
"android.app.supervision.flags-aconfig",
|
||||||
"android.provider.flags-aconfig",
|
"android.provider.flags-aconfig",
|
||||||
"android.security.flags-aconfig",
|
"android.security.flags-aconfig",
|
||||||
"android.view.contentprotection.flags-aconfig",
|
"android.view.contentprotection.flags-aconfig",
|
||||||
|
@@ -2817,6 +2817,15 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".supervision.ConfirmSupervisionCredentialsActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:featureFlag="android.app.supervision.flags.supervision_manager_apis">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.app.supervision.action.CONFIRM_SUPERVISION_CREDENTIALS" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".SetupRedactionInterstitial"
|
<activity android:name=".SetupRedactionInterstitial"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
@@ -14309,5 +14309,7 @@ Data usage charges may apply.</string>
|
|||||||
<!-- Title for web content filters browser category allow all sites option [CHAR LIMIT=60] -->
|
<!-- Title for web content filters browser category allow all sites option [CHAR LIMIT=60] -->
|
||||||
<string name="supervision_web_content_filters_browser_allow_all_sites_title">Allow all sites</string>
|
<string name="supervision_web_content_filters_browser_allow_all_sites_title">Allow all sites</string>
|
||||||
<!-- Generic content description that is attached to the preview illustration at the top of an Accessibility feature toggle page. [CHAR LIMIT=NONE] -->
|
<!-- Generic content description that is attached to the preview illustration at the top of an Accessibility feature toggle page. [CHAR LIMIT=NONE] -->
|
||||||
|
<!-- Title for supervision PIN verification screen [CHAR LIMIT=60] -->
|
||||||
|
<string name="supervision_full_screen_pin_verification_title">Enter supervision PIN</string>
|
||||||
<string name="accessibility_illustration_content_description"><xliff:g id="feature" example="Select to Speak">%1$s</xliff:g> animation</string>
|
<string name="accessibility_illustration_content_description"><xliff:g id="feature" example="Select to Speak">%1$s</xliff:g> animation</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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.settings.supervision
|
||||||
|
|
||||||
|
import android.Manifest.permission.USE_BIOMETRIC
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.hardware.biometrics.BiometricManager
|
||||||
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
|
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.CancellationSignal
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import com.android.settings.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity for confirming supervision credentials using device credential authentication.
|
||||||
|
*
|
||||||
|
* This activity displays an authentication prompt to the user, requiring them to authenticate using
|
||||||
|
* their device credentials (PIN, pattern, or password). It is specifically designed for verifying
|
||||||
|
* credentials for supervision purposes.
|
||||||
|
*
|
||||||
|
* It returns `Activity.RESULT_OK` if authentication succeeds, and `Activity.RESULT_CANCELED` if
|
||||||
|
* authentication fails or is canceled by the user.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* 1. Start this activity using `startActivityForResult()`.
|
||||||
|
* 2. Handle the result in `onActivityResult()`.
|
||||||
|
*
|
||||||
|
* Permissions:
|
||||||
|
* - Requires `android.permission.USE_BIOMETRIC`.
|
||||||
|
*/
|
||||||
|
class ConfirmSupervisionCredentialsActivity : FragmentActivity() {
|
||||||
|
private val mAuthenticationCallback =
|
||||||
|
object : AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
Log.w(TAG, "onAuthenticationError(errorCode=$errorCode, errString=$errString)")
|
||||||
|
setResult(Activity.RESULT_CANCELED)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) {
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
setResult(Activity.RESULT_CANCELED)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(USE_BIOMETRIC)
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
// TODO(b/392961554): Check if caller is the SYSTEM_SUPERVISION role holder. Call
|
||||||
|
// RoleManager#getRoleHolders(SYSTEM_SUPERVISION) and check if getCallingPackage() is in the
|
||||||
|
// list.
|
||||||
|
if (checkCallingOrSelfPermission(USE_BIOMETRIC) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
showBiometricPrompt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(USE_BIOMETRIC)
|
||||||
|
fun showBiometricPrompt() {
|
||||||
|
// TODO(b/392961554): adapts to new user profile type to trigger PIN verification dialog.
|
||||||
|
val biometricPrompt =
|
||||||
|
BiometricPrompt.Builder(this)
|
||||||
|
.setTitle(getString(R.string.supervision_full_screen_pin_verification_title))
|
||||||
|
.setConfirmationRequired(true)
|
||||||
|
.setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
|
||||||
|
.build()
|
||||||
|
biometricPrompt.authenticate(
|
||||||
|
CancellationSignal(),
|
||||||
|
ContextCompat.getMainExecutor(this),
|
||||||
|
mAuthenticationCallback,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// TODO(b/392961554): remove this tag and use shared tag after http://ag/31997167 is
|
||||||
|
// submitted.
|
||||||
|
const val TAG = "SupervisionSettings"
|
||||||
|
}
|
||||||
|
}
|
@@ -56,7 +56,7 @@ class SupervisionDashboardScreen : PreferenceScreenCreator {
|
|||||||
|
|
||||||
override fun getPreferenceHierarchy(context: Context) =
|
override fun getPreferenceHierarchy(context: Context) =
|
||||||
preferenceHierarchy(context, this) {
|
preferenceHierarchy(context, this) {
|
||||||
+SupervisionMainSwitchPreference()
|
+SupervisionMainSwitchPreference(context)
|
||||||
+TitlelessPreferenceGroup(SUPERVISION_DYNAMIC_GROUP_1) += {
|
+TitlelessPreferenceGroup(SUPERVISION_DYNAMIC_GROUP_1) += {
|
||||||
+SupervisionWebContentFiltersScreen.KEY
|
+SupervisionWebContentFiltersScreen.KEY
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.supervision
|
package com.android.settings.supervision
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.supervision.SupervisionManager
|
import android.app.supervision.SupervisionManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settingslib.datastore.KeyValueStore
|
import com.android.settingslib.datastore.KeyValueStore
|
||||||
@@ -32,19 +34,22 @@ import com.android.settingslib.preference.MainSwitchPreferenceBinding
|
|||||||
import com.android.settingslib.preference.forEachRecursively
|
import com.android.settingslib.preference.forEachRecursively
|
||||||
|
|
||||||
/** Main toggle to enable or disable device supervision. */
|
/** Main toggle to enable or disable device supervision. */
|
||||||
class SupervisionMainSwitchPreference :
|
class SupervisionMainSwitchPreference(context: Context) :
|
||||||
MainSwitchPreference(KEY, R.string.device_supervision_switch_title),
|
MainSwitchPreference(KEY, R.string.device_supervision_switch_title),
|
||||||
PreferenceSummaryProvider,
|
PreferenceSummaryProvider,
|
||||||
MainSwitchPreferenceBinding,
|
MainSwitchPreferenceBinding,
|
||||||
Preference.OnPreferenceChangeListener,
|
Preference.OnPreferenceChangeListener,
|
||||||
PreferenceLifecycleProvider {
|
PreferenceLifecycleProvider {
|
||||||
|
|
||||||
|
private val supervisionMainSwitchStorage = SupervisionMainSwitchStorage(context)
|
||||||
|
private lateinit var lifeCycleContext: PreferenceLifecycleContext
|
||||||
|
|
||||||
// TODO(b/383568136): Make presence of summary conditional on whether PIN
|
// TODO(b/383568136): Make presence of summary conditional on whether PIN
|
||||||
// has been set up before or not.
|
// has been set up before or not.
|
||||||
override fun getSummary(context: Context): CharSequence? =
|
override fun getSummary(context: Context): CharSequence? =
|
||||||
context.getString(R.string.device_supervision_switch_no_pin_summary)
|
context.getString(R.string.device_supervision_switch_no_pin_summary)
|
||||||
|
|
||||||
override fun storage(context: Context): KeyValueStore = SupervisionMainSwitchStorage(context)
|
override fun storage(context: Context): KeyValueStore = supervisionMainSwitchStorage
|
||||||
|
|
||||||
override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
|
override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
|
||||||
ReadWritePermit.DISALLOW
|
ReadWritePermit.DISALLOW
|
||||||
@@ -55,26 +60,49 @@ class SupervisionMainSwitchPreference :
|
|||||||
override val sensitivityLevel: Int
|
override val sensitivityLevel: Int
|
||||||
get() = SensitivityLevel.HIGH_SENSITIVITY
|
get() = SensitivityLevel.HIGH_SENSITIVITY
|
||||||
|
|
||||||
|
override fun onCreate(context: PreferenceLifecycleContext) {
|
||||||
|
lifeCycleContext = context
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume(context: PreferenceLifecycleContext) {
|
||||||
|
updateDependentPreferencesEnabledState(
|
||||||
|
context.findPreference<Preference>(KEY),
|
||||||
|
supervisionMainSwitchStorage.getBoolean(KEY)!!,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(
|
||||||
|
context: PreferenceLifecycleContext,
|
||||||
|
requestCode: Int,
|
||||||
|
resultCode: Int,
|
||||||
|
data: Intent?,
|
||||||
|
): Boolean {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
val mainSwitchPreference =
|
||||||
|
context.requirePreference<com.android.settingslib.widget.MainSwitchPreference>(KEY)
|
||||||
|
val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!!
|
||||||
|
mainSwitchPreference.setChecked(newValue)
|
||||||
|
updateDependentPreferencesEnabledState(mainSwitchPreference, newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
|
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
|
||||||
super.bind(preference, metadata)
|
super.bind(preference, metadata)
|
||||||
preference.onPreferenceChangeListener = this
|
preference.onPreferenceChangeListener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume(context: PreferenceLifecycleContext) {
|
|
||||||
val currentValue = storage(context.applicationContext)?.getBoolean(key) ?: false
|
|
||||||
|
|
||||||
updateDependentPreferencesEnabledState(
|
|
||||||
context.findPreference<Preference>(KEY),
|
|
||||||
currentValue,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
|
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
|
||||||
if (newValue !is Boolean) return true
|
if (newValue !is Boolean) return true
|
||||||
|
|
||||||
updateDependentPreferencesEnabledState(preference, newValue)
|
val intent = Intent(lifeCycleContext, ConfirmSupervisionCredentialsActivity::class.java)
|
||||||
|
lifeCycleContext.startActivityForResult(
|
||||||
return true
|
intent,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDependentPreferencesEnabledState(
|
private fun updateDependentPreferencesEnabledState(
|
||||||
@@ -83,9 +111,8 @@ class SupervisionMainSwitchPreference :
|
|||||||
) {
|
) {
|
||||||
preference?.parent?.forEachRecursively {
|
preference?.parent?.forEachRecursively {
|
||||||
if (
|
if (
|
||||||
it.parent?.key?.toString() ==
|
it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
|
||||||
SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
|
it.key == SupervisionPinManagementScreen.KEY
|
||||||
it.key?.toString() == SupervisionPinManagementScreen.KEY
|
|
||||||
) {
|
) {
|
||||||
it.isEnabled = isChecked
|
it.isEnabled = isChecked
|
||||||
}
|
}
|
||||||
@@ -103,7 +130,6 @@ class SupervisionMainSwitchPreference :
|
|||||||
as T
|
as T
|
||||||
|
|
||||||
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
||||||
// TODO(b/392694561): add PIN protection to main toggle.
|
|
||||||
if (key == KEY && value is Boolean) {
|
if (key == KEY && value is Boolean) {
|
||||||
val supervisionManager = context.getSystemService(SupervisionManager::class.java)
|
val supervisionManager = context.getSystemService(SupervisionManager::class.java)
|
||||||
supervisionManager?.setSupervisionEnabled(value)
|
supervisionManager?.setSupervisionEnabled(value)
|
||||||
@@ -113,5 +139,6 @@ class SupervisionMainSwitchPreference :
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY = "device_supervision_switch"
|
const val KEY = "device_supervision_switch"
|
||||||
|
const val REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.supervision
|
package com.android.settings.supervision
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.supervision.flags.Flags
|
import android.app.supervision.flags.Flags
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.platform.test.annotations.DisableFlags
|
import android.platform.test.annotations.DisableFlags
|
||||||
@@ -24,6 +25,7 @@ import androidx.fragment.app.testing.FragmentScenario
|
|||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.supervision.SupervisionMainSwitchPreference.Companion.REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS
|
||||||
import com.android.settingslib.widget.MainSwitchPreference
|
import com.android.settingslib.widget.MainSwitchPreference
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@@ -57,7 +59,7 @@ class SupervisionDashboardScreenTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
||||||
fun toggleMainSwitch_disablesChildPreferences() {
|
fun toggleMainSwitch_pinVerificationSucceeded_enablesChildPreferences() {
|
||||||
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
||||||
fragment ->
|
fragment ->
|
||||||
val mainSwitchPreference =
|
val mainSwitchPreference =
|
||||||
@@ -68,8 +70,38 @@ class SupervisionDashboardScreenTest {
|
|||||||
assertThat(childPreference.isEnabled).isFalse()
|
assertThat(childPreference.isEnabled).isFalse()
|
||||||
|
|
||||||
mainSwitchPreference.performClick()
|
mainSwitchPreference.performClick()
|
||||||
|
// Pretend the PIN verification succeeded.
|
||||||
|
fragment.onActivityResult(
|
||||||
|
requestCode = REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
resultCode = Activity.RESULT_OK,
|
||||||
|
data = null,
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(childPreference.isEnabled).isTrue()
|
assertThat(childPreference.isEnabled).isTrue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
||||||
|
fun toggleMainSwitch_pinVerificationFailed_childPreferencesRemainDisabled() {
|
||||||
|
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
||||||
|
fragment ->
|
||||||
|
val mainSwitchPreference =
|
||||||
|
fragment.findPreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)!!
|
||||||
|
val childPreference =
|
||||||
|
fragment.findPreference<Preference>(SupervisionPinManagementScreen.KEY)!!
|
||||||
|
|
||||||
|
assertThat(childPreference.isEnabled).isFalse()
|
||||||
|
|
||||||
|
mainSwitchPreference.performClick()
|
||||||
|
// Pretend the PIN verification failed.
|
||||||
|
fragment.onActivityResult(
|
||||||
|
requestCode = REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
resultCode = Activity.RESULT_CANCELED,
|
||||||
|
data = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(childPreference.isEnabled).isFalse()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,25 +15,33 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.supervision
|
package com.android.settings.supervision
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.supervision.SupervisionManager
|
import android.app.supervision.SupervisionManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.preference.Preference
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.supervision.SupervisionMainSwitchPreference.Companion.REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS
|
||||||
|
import com.android.settingslib.metadata.PreferenceLifecycleContext
|
||||||
import com.android.settingslib.preference.createAndBindWidget
|
import com.android.settingslib.preference.createAndBindWidget
|
||||||
import com.android.settingslib.widget.MainSwitchPreference
|
import com.android.settingslib.widget.MainSwitchPreference
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.argumentCaptor
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.eq
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.never
|
||||||
import org.mockito.kotlin.stub
|
import org.mockito.kotlin.stub
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class SupervisionMainSwitchPreferenceTest {
|
class SupervisionMainSwitchPreferenceTest {
|
||||||
private val preference = SupervisionMainSwitchPreference()
|
private val mockLifeCycleContext = mock<PreferenceLifecycleContext>()
|
||||||
|
|
||||||
private val mockSupervisionManager = mock<SupervisionManager>()
|
private val mockSupervisionManager = mock<SupervisionManager>()
|
||||||
|
|
||||||
private val appContext: Context = ApplicationProvider.getApplicationContext()
|
private val appContext: Context = ApplicationProvider.getApplicationContext()
|
||||||
@@ -46,6 +54,13 @@ class SupervisionMainSwitchPreferenceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val preference = SupervisionMainSwitchPreference(context)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
preference.onCreate(mockLifeCycleContext)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun checked_supervisionEnabled_returnTrue() {
|
fun checked_supervisionEnabled_returnTrue() {
|
||||||
setSupervisionEnabled(true)
|
setSupervisionEnabled(true)
|
||||||
@@ -61,7 +76,7 @@ class SupervisionMainSwitchPreferenceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun toggleOn() {
|
fun toggleOn_triggersPinVerification() {
|
||||||
setSupervisionEnabled(false)
|
setSupervisionEnabled(false)
|
||||||
val widget = getMainSwitchPreference()
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
@@ -69,26 +84,90 @@ class SupervisionMainSwitchPreferenceTest {
|
|||||||
|
|
||||||
widget.performClick()
|
widget.performClick()
|
||||||
|
|
||||||
|
verifyConfirmSupervisionCredentialsActivityStarted()
|
||||||
|
assertThat(widget.isChecked).isFalse()
|
||||||
|
verify(mockSupervisionManager, never()).setSupervisionEnabled(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toggleOn_pinVerificationSucceeded_supervisionEnabled() {
|
||||||
|
setSupervisionEnabled(false)
|
||||||
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
|
assertThat(widget.isChecked).isFalse()
|
||||||
|
|
||||||
|
preference.onActivityResult(
|
||||||
|
mockLifeCycleContext,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
Activity.RESULT_OK,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(widget.isChecked).isTrue()
|
assertThat(widget.isChecked).isTrue()
|
||||||
verify(mockSupervisionManager).setSupervisionEnabled(true)
|
verify(mockSupervisionManager).setSupervisionEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun toggleOff() {
|
fun toggleOff_pinVerificationSucceeded_supervisionDisabled() {
|
||||||
setSupervisionEnabled(true)
|
setSupervisionEnabled(true)
|
||||||
val widget = getMainSwitchPreference()
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
assertThat(widget.isChecked).isTrue()
|
assertThat(widget.isChecked).isTrue()
|
||||||
|
|
||||||
widget.performClick()
|
preference.onActivityResult(
|
||||||
|
mockLifeCycleContext,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
Activity.RESULT_OK,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(widget.isChecked).isFalse()
|
assertThat(widget.isChecked).isFalse()
|
||||||
verify(mockSupervisionManager).setSupervisionEnabled(false)
|
verify(mockSupervisionManager).setSupervisionEnabled(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMainSwitchPreference(): MainSwitchPreference =
|
@Test
|
||||||
preference.createAndBindWidget(context)
|
fun toggleOff_pinVerificationFailed_supervisionNotEnabled() {
|
||||||
|
setSupervisionEnabled(true)
|
||||||
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
|
assertThat(widget.isChecked).isTrue()
|
||||||
|
|
||||||
|
preference.onActivityResult(
|
||||||
|
mockLifeCycleContext,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
Activity.RESULT_CANCELED,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(widget.isChecked).isTrue()
|
||||||
|
verify(mockSupervisionManager, never()).setSupervisionEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setSupervisionEnabled(enabled: Boolean) =
|
private fun setSupervisionEnabled(enabled: Boolean) =
|
||||||
mockSupervisionManager.stub { on { isSupervisionEnabled } doReturn enabled }
|
mockSupervisionManager.stub { on { isSupervisionEnabled } doReturn enabled }
|
||||||
|
|
||||||
|
private fun getMainSwitchPreference(): MainSwitchPreference {
|
||||||
|
val widget: MainSwitchPreference = preference.createAndBindWidget(context)
|
||||||
|
|
||||||
|
mockLifeCycleContext.stub {
|
||||||
|
on { findPreference<Preference>(SupervisionMainSwitchPreference.KEY) } doReturn widget
|
||||||
|
on {
|
||||||
|
requirePreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)
|
||||||
|
} doReturn widget
|
||||||
|
}
|
||||||
|
return widget
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyConfirmSupervisionCredentialsActivityStarted() {
|
||||||
|
val intentCaptor = argumentCaptor<Intent>()
|
||||||
|
verify(mockLifeCycleContext)
|
||||||
|
.startActivityForResult(
|
||||||
|
intentCaptor.capture(),
|
||||||
|
eq(REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS),
|
||||||
|
eq(null),
|
||||||
|
)
|
||||||
|
assertThat(intentCaptor.allValues.size).isEqualTo(1)
|
||||||
|
assertThat(intentCaptor.firstValue.component?.className)
|
||||||
|
.isEqualTo(ConfirmSupervisionCredentialsActivity::class.java.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user