Merge "Fix dialog leak in RequestPermissionActivity" into udc-dev
diff --git a/res/drawable/ic_stylus.xml b/res/drawable/ic_stylus.xml
new file mode 100644
index 0000000..eb52fec
--- /dev/null
+++ b/res/drawable/ic_stylus.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?android:attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M167,840Q146,845 130.5,829.5Q115,814 120,793L160,602L358,800L167,840ZM358,800L160,602L618,144Q641,121 675,121Q709,121 732,144L816,228Q839,251 839,285Q839,319 816,342L358,800ZM675,200L261,614L346,699L760,285Q760,285 760,285Q760,285 760,285L675,200Q675,200 675,200Q675,200 675,200Z"/>
+</vector>
\ No newline at end of file
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
index 947c5ac..1187c59 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
@@ -165,8 +165,7 @@
         }
         mUsiPreference.setKey(PREF_KEY);
         mUsiPreference.setTitle(R.string.stylus_connected_devices_title);
-        // TODO(b/250909304): pending actual icon visD
-        mUsiPreference.setIcon(R.drawable.ic_edit);
+        mUsiPreference.setIcon(R.drawable.ic_stylus);
         mUsiPreference.setOnPreferenceClickListener((Preference p) -> {
             mMetricsFeatureProvider.logClickedPreference(p, mFragment.getMetricsCategory());
             launchDeviceDetails();
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java b/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
index 379815b..23db3cb 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
@@ -70,8 +70,7 @@
 
         ImageView iconView = mHeaderPreference.findViewById(R.id.entity_header_icon);
         if (iconView != null) {
-            // TODO(b/250909304): get proper icon once VisD ready
-            iconView.setImageResource(R.drawable.ic_edit);
+            iconView.setImageResource(R.drawable.ic_stylus);
             iconView.setContentDescription("Icon for stylus");
         }
         refresh();
diff --git a/src/com/android/settings/spa/SpaActivity.kt b/src/com/android/settings/spa/SpaActivity.kt
index 27f7241..2b52b21 100644
--- a/src/com/android/settings/spa/SpaActivity.kt
+++ b/src/com/android/settings/spa/SpaActivity.kt
@@ -22,14 +22,34 @@
 import android.os.RemoteException
 import android.os.UserHandle
 import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
 import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.util.SESSION_BROWSE
 import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
 import com.android.settingslib.spa.framework.util.appendSpaParams
+import com.google.android.setupcompat.util.WizardManagerHelper
 
 class SpaActivity : BrowseActivity() {
+    override fun isPageEnabled(page: SettingsPage) =
+        super.isPageEnabled(page) && !isSuwAndPageBlocked(page.sppName)
+
     companion object {
         private const val TAG = "SpaActivity"
+
+        /** The pages that blocked from SUW. */
+        private val SuwBlockedPages = setOf(AppInfoSettingsProvider.name)
+
+        @VisibleForTesting
+        fun Context.isSuwAndPageBlocked(name: String): Boolean =
+            if (name in SuwBlockedPages && !WizardManagerHelper.isDeviceProvisioned(this)) {
+                Log.w(TAG, "$name blocked before SUW completed.");
+                true
+            } else {
+                false
+            }
+
         @JvmStatic
         fun Context.startSpaActivity(destination: String) {
             val intent = Intent(this, SpaActivity::class.java)
diff --git a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
index 9b36335..527c6d9 100644
--- a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
+++ b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
@@ -19,12 +19,14 @@
 import android.Manifest
 import android.app.AlarmManager
 import android.app.compat.CompatChanges
+import android.app.settings.SettingsEnums
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.os.PowerExemptionManager
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.livedata.observeAsState
 import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.IPackageManagers
@@ -85,6 +87,17 @@
 
     override fun setAllowed(record: AlarmsAndRemindersAppRecord, newAllowed: Boolean) {
         record.controller.setAllowed(newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        FeatureFactory.getFactory(context).metricsFeatureProvider.action(
+            SettingsEnums.PAGE_UNKNOWN,
+            SettingsEnums.ACTION_ALARMS_AND_REMINDERS_TOGGLE,
+            SettingsEnums.ALARMS_AND_REMINDERS,
+            "",
+            if (newAllowed) 1 else 0
+        )
     }
 
     private fun createRecord(
diff --git a/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt b/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt
index 6466e03..16520fa 100644
--- a/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt
@@ -18,9 +18,12 @@
 
 import android.Manifest
 import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
 import android.content.Context
 import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
 import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
 
 object AllFilesAccessAppListProvider : TogglePermissionAppListProvider {
@@ -35,4 +38,17 @@
     override val appOp = AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE
     override val permission = Manifest.permission.MANAGE_EXTERNAL_STORAGE
     override val setModeByUid = true
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        val category = when {
+            newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_ALLOW
+            else -> SettingsEnums.APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY
+        }
+        FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, category, "")
+    }
 }
diff --git a/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt b/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt
index d3cd2b5..7812675 100644
--- a/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt
@@ -18,9 +18,12 @@
 
 import android.Manifest
 import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
 import android.content.Context
 import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
 import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
 
 object DisplayOverOtherAppsAppListProvider : TogglePermissionAppListProvider {
@@ -34,4 +37,17 @@
     override val footerResId = R.string.allow_overlay_description
     override val appOp = AppOpsManager.OP_SYSTEM_ALERT_WINDOW
     override val permission = Manifest.permission.SYSTEM_ALERT_WINDOW
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        val category = when {
+            newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_APPDRAW_ALLOW
+            else -> SettingsEnums.APP_SPECIAL_PERMISSION_APPDRAW_DENY
+        }
+        FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, category, "")
+    }
 }
diff --git a/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt b/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt
index 6c7678a..e8935e6 100644
--- a/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt
@@ -18,9 +18,12 @@
 
 import android.Manifest
 import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
 import android.content.Context
 import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
 import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
 
 object MediaManagementAppsAppListProvider : TogglePermissionAppListProvider {
@@ -35,4 +38,19 @@
     override val appOp = AppOpsManager.OP_MANAGE_MEDIA
     override val permission = Manifest.permission.MANAGE_MEDIA
     override val setModeByUid = true
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        FeatureFactory.getFactory(context).metricsFeatureProvider.action(
+            SettingsEnums.PAGE_UNKNOWN,
+            SettingsEnums.ACTION_MEDIA_MANAGEMENT_APPS_TOGGLE,
+            SettingsEnums.MEDIA_MANAGEMENT_APPS,
+            "",
+            if (newAllowed) 1 else 0
+        )
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt b/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt
index 9a70871..668cc8c 100644
--- a/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt
+++ b/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt
@@ -18,9 +18,12 @@
 
 import android.Manifest
 import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
 import android.content.Context
 import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
 import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
 
 object ModifySystemSettingsAppListProvider : TogglePermissionAppListProvider {
@@ -34,4 +37,17 @@
     override val footerResId = R.string.write_settings_description
     override val appOp = AppOpsManager.OP_WRITE_SETTINGS
     override val permission = Manifest.permission.WRITE_SETTINGS
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        val category = when {
+            newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW
+            else -> SettingsEnums.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY
+        }
+        FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, category, "")
+    }
 }
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
index 46b956e..1b2a7b1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
@@ -21,33 +21,71 @@
 import android.net.Uri
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.settings.spa.SpaActivity.Companion.isSuwAndPageBlocked
 import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
 import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
+import com.android.settings.spa.app.AllAppListPageProvider
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
 import com.android.settingslib.spa.framework.util.KEY_DESTINATION
+import com.google.android.setupcompat.util.WizardManagerHelper
 import com.google.common.truth.Truth.assertThat
+import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Answers
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+import org.mockito.Mockito.`when` as whenever
 
 @RunWith(AndroidJUnit4::class)
 class SpaActivityTest {
-    @get:Rule
-    val mockito: MockitoRule = MockitoJUnit.rule()
+    private lateinit var mockSession: MockitoSession
 
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    @Mock
     private lateinit var context: Context
 
     @Before
     fun setUp() {
-        `when`(context.applicationContext.packageName).thenReturn("com.android.settings")
+        mockSession = ExtendedMockito.mockitoSession()
+            .initMocks(this)
+            .mockStatic(WizardManagerHelper::class.java)
+            .strictness(Strictness.LENIENT)
+            .startMocking()
+        whenever(context.applicationContext).thenReturn(context)
+    }
+
+    @After
+    fun tearDown() {
+        mockSession.finishMocking()
+    }
+
+    @Test
+    fun isSuwAndPageBlocked_regularPage_notBlocked() {
+        val isBlocked = context.isSuwAndPageBlocked(AllAppListPageProvider.name)
+
+        assertThat(isBlocked).isFalse()
+    }
+
+    @Test
+    fun isSuwAndPageBlocked_blocklistedPageInSuw_blocked() {
+        whenever(WizardManagerHelper.isDeviceProvisioned(context)).thenReturn(false)
+
+        val isBlocked = context.isSuwAndPageBlocked(AppInfoSettingsProvider.name)
+
+        assertThat(isBlocked).isTrue()
+    }
+
+    @Test
+    fun isSuwAndPageBlocked_blocklistedPageNotInSuw_notBlocked() {
+        whenever(WizardManagerHelper.isDeviceProvisioned(context)).thenReturn(true)
+
+        val isBlocked = context.isSuwAndPageBlocked(AppInfoSettingsProvider.name)
+
+        assertThat(isBlocked).isFalse()
     }
 
     @Test