diff --git a/res/values/strings.xml b/res/values/strings.xml index a3760c547e8..02b7a4c3eec 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9520,6 +9520,13 @@ Can access all files + + Voice activation apps + + Allow voice activation + + Voice activation turns-on approved apps, hands-free, using voice command.\n\nUntill activated, none of these apps can directly access your microphone.Instead, this device uses built-in proteced adaptive sensing to turn-on aprroved apps for you.\n\nMore about protected adaptive sensing + Full screen notifications diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml index b3f3f7dd5da..3f3d75d2daf 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -99,6 +99,11 @@ android:title="@string/full_screen_intent_title" settings:controller="com.android.settings.spa.app.specialaccess.UseFullScreenIntentPreferenceController" /> + + SettingsEnums.APP_SPECIAL_PERMISSION_RECEIVE_SANDBOX_TRIGGER_AUDIO_ALLOW + else -> SettingsEnums.APP_SPECIAL_PERMISSION_RECEIVE_SANDBOX_TRIGGER_AUDIO_DENY + } + /** + * Leave the package string empty as we should not log the package names for the collected + * metrics. + */ + FeatureFactory.featureFactory.metricsFeatureProvider.action(context, category, "") + } +} \ No newline at end of file diff --git a/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceController.kt b/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceController.kt new file mode 100644 index 00000000000..27d4b4b9035 --- /dev/null +++ b/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceController.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 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.spa.app.specialaccess + +import android.content.Context +import androidx.preference.Preference +import com.android.settings.core.BasePreferenceController +import com.android.settings.flags.Flags +import com.android.settings.spa.SpaActivity.Companion.startSpaActivity + +class VoiceActivationAppsPreferenceController(context: Context, preferenceKey: String) : + BasePreferenceController(context, preferenceKey) { + override fun getAvailabilityStatus() = + if (Flags.enableVoiceActivationAppsInSettings()) AVAILABLE + else CONDITIONALLY_UNAVAILABLE + + override fun handlePreferenceTreeClick(preference: Preference): Boolean { + if (preference.key == mPreferenceKey) { + mContext.startSpaActivity(VoiceActivationAppsListProvider.getAppListRoute()) + return true + } + return false + } +} \ No newline at end of file diff --git a/tests/spa_unit/Android.bp b/tests/spa_unit/Android.bp index 28a26672465..c3e99f75dcf 100644 --- a/tests/spa_unit/Android.bp +++ b/tests/spa_unit/Android.bp @@ -34,6 +34,7 @@ android_test { "androidx.compose.runtime_runtime", "androidx.test.ext.junit", "androidx.test.runner", + "flag-junit", "mockito-target-extended-minus-junit4", ], jni_libs: [ diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceControllerTest.kt new file mode 100644 index 00000000000..2127497ded8 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceControllerTest.kt @@ -0,0 +1,65 @@ +package com.android.settings.spa.app.specialaccess + +import android.content.Context +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import androidx.preference.Preference +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import com.android.settings.flags.Flags +import com.google.common.truth.Truth.assertThat + +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.spy +import org.mockito.kotlin.whenever + +@RunWith(AndroidJUnit4::class) +class VoiceActivationAppsPreferenceControllerTest { + + @get:Rule + val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + doNothing().whenever(mock).startActivity(any()) + } + + private val matchedPreference = Preference(context).apply { key = preferenceKey } + + private val misMatchedPreference = Preference(context).apply { key = testPreferenceKey } + + private val controller = VoiceActivationAppsPreferenceController(context, preferenceKey) + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_VOICE_ACTIVATION_APPS_IN_SETTINGS) + fun getAvailabilityStatus_enableVoiceActivationApps_returnAvailable() { + assertThat(controller.isAvailable).isTrue() + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_ENABLE_VOICE_ACTIVATION_APPS_IN_SETTINGS) + fun getAvailableStatus_disableVoiceActivationApps_returnConditionallyUnavailable() { + assertThat(controller.isAvailable).isFalse() + } + + @Test + fun handlePreferenceTreeClick_keyMatched_returnTrue() { + assertThat(controller.handlePreferenceTreeClick(matchedPreference)).isTrue() + } + + @Test + fun handlePreferenceTreeClick_keyMisMatched_returnFalse() { + assertThat(controller.handlePreferenceTreeClick(misMatchedPreference)).isFalse() + } + + companion object { + private const val preferenceKey: String = "voice_activation_apps" + private const val testPreferenceKey: String = "test_key" + } +} \ No newline at end of file diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsTest.kt new file mode 100644 index 00000000000..7d636b3f70a --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsTest.kt @@ -0,0 +1,50 @@ +package com.android.settings.spa.app.specialaccess + +import android.Manifest +import android.app.AppOpsManager +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class VoiceActivationAppsTest { + private val context: Context = ApplicationProvider.getApplicationContext() + + private val listModel = VoiceActivationAppsListModel(context) + + @Test + fun pageTitleResId() { + assertThat(listModel.pageTitleResId).isEqualTo(R.string.voice_activation_apps_title) + } + + @Test + fun switchTitleResId() { + assertThat(listModel.switchTitleResId).isEqualTo(R.string.permit_voice_activation_apps) + } + + @Test + fun footerResId() { + assertThat(listModel.footerResId) + .isEqualTo(R.string.allow_voice_activation_apps_description) + } + + @Test + fun appOp() { + assertThat(listModel.appOp).isEqualTo(AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO) + } + + @Test + fun permission() { + assertThat(listModel.permission).isEqualTo( + Manifest.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO) + } + + @Test + fun setModeByUid() { + assertThat(listModel.setModeByUid).isTrue() + } +} \ No newline at end of file