summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Faye Yan <fayey@google.com> 2024-06-21 22:07:02 +0000
committer Faye Yan <fayey@google.com> 2024-07-24 00:34:34 +0000
commitee17b3ec38f649354ba3d131d6490dedf6d7a22f (patch)
treea1c8798aae3d99a84ccdd490f9d1cf952d5f6dd3
parent1174eab1d2e09ff9516baaa3db83d42b6410e610 (diff)
[ECM Backport] Add allow restricted settings into options menu of App
permissions. This change implements the UX change for ECM Backport to T and U builds. In V, no UX change, "allow restricted settings" is in the options menu of AppInfo screen. In U, the "allow restricted settings" is added into the options menu of App permissions screen. In T, the "allow restricted settings" is added into the options menu of App permisisons screen. Flag: com.android.permission.flags.enhanced_confirmation_backport_enabled Bug: 347876543 Test: Manual tested on T, U, V devices, atest to be added Test: atest EnhancedConfirmationBackportTest LOW_COVERAGE_REASON=FLAG_NOT_ENABLED Change-Id: I6aee8baccb2ea60c39d6c67b097f8d2dcfc2c757
-rw-r--r--PermissionController/res/values/strings.xml3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java20
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt33
-rw-r--r--flags/flags.aconfig9
-rw-r--r--tests/cts/permissionui/Android.bp1
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt15
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationBackportTest.kt146
8 files changed, 228 insertions, 0 deletions
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index 698a9bbb4..57268f670 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -1992,6 +1992,9 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<!-- A string representing a message (sms, email, etc.) telling the user about a one time password. Used for testing [CHAR LIMIT=NONE] -->
<string name="test_otp_msg">Your one time password is 132435</string>
+ <!-- [CHAR LIMIT=50] Manage applications, unlock restricted setting from app permissions options menu -->
+ <string name="allow_restricted_settings">Allow restricted settings</string>
+
<!-- START ENHANCED CONFIRMATION DIALOG -->
<!--Title for dialog displayed to tell user that settings are blocked by setting restrictions [CHAR LIMIT=50] -->
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
index eff5738fc..e8d0fb22b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
@@ -252,6 +252,12 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
mPackageName, mUser));
return true;
}
+
+ case MENU_ALLOW_RESTRICTED_SETTINGS: {
+ mViewModel.clearRestriction();
+ getActivity().invalidateOptionsMenu();
+ return true;
+ }
}
return super.onOptionsItemSelected(item);
}
@@ -266,6 +272,20 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
getClass().getName());
}
}
+
+ if (SdkLevel.isAtLeastT() && !SdkLevel.isAtLeastV()
+ && Flags.enhancedConfirmationBackportEnabled()) {
+ menu.add(Menu.NONE, MENU_ALLOW_RESTRICTED_SETTINGS, Menu.NONE,
+ R.string.allow_restricted_settings);
+ }
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
+ final MenuItem allowRestrictedSettingsMenu = menu.findItem(MENU_ALLOW_RESTRICTED_SETTINGS);
+ if (allowRestrictedSettingsMenu != null) {
+ allowRestrictedSettingsMenu.setVisible(mViewModel.isClearRestrictedAllowed());
+ }
}
private static void bindUi(SettingsWithLargeHeader fragment, String packageName,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java
index 17e72b413..a44c761a1 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java
@@ -42,6 +42,7 @@ public abstract class PermissionsFrameFragment extends PreferenceFragmentCompat
static final int MENU_ALL_PERMS = Menu.FIRST + 1;
public static final int MENU_SHOW_SYSTEM = Menu.FIRST + 2;
public static final int MENU_HIDE_SYSTEM = Menu.FIRST + 3;
+ static final int MENU_ALLOW_RESTRICTED_SETTINGS = Menu.FIRST + 4;
private ViewGroup mPreferencesContainer;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
index ee0c5d2f2..f92cc08d7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
@@ -17,6 +17,7 @@
package com.android.permissioncontroller.permission.ui.model
import android.Manifest
+import android.annotation.SuppressLint
import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_IGNORED
@@ -31,6 +32,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.android.modules.utils.build.SdkLevel
+import com.android.permission.flags.Flags
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION
@@ -128,6 +130,37 @@ class AppPermissionGroupsViewModel(
private val fullStoragePermsLiveData = FullStoragePermissionAppsLiveData
private val packagePermsExternalDeviceLiveData =
PackagePermissionsExternalDeviceLiveData[packageName, user]
+ private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!!
+ private val packageManager = app.packageManager
+
+ /** Check if the application is in restricted settings mode. */
+ @SuppressLint("NewApi")
+ fun isClearRestrictedAllowed(): Boolean {
+ if (Flags.enhancedConfirmationBackportEnabled()) {
+ // TODO(b/347876543): Replace this when EnhancedConfirmtionServiceImpl is
+ // available.
+ val isRestricted =
+ appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS,
+ packageManager.getApplicationInfoAsUser(packageName, 0, user).uid,
+ packageName, null, null) == MODE_IGNORED
+ return isRestricted
+ }
+ return false
+ }
+
+ /** Allow restricted settings on the applications. */
+ @SuppressLint("NewApi")
+ fun clearRestriction() {
+ if (Flags.enhancedConfirmationBackportEnabled()) {
+ // TODO(b/347876543): Replace this when EnhancedConfirmationServiceImpl is
+ // available.
+ appOpsManager.setMode(
+ AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS,
+ packageManager.getApplicationInfoAsUser(packageName, 0, user).uid,
+ packageName, MODE_ALLOWED
+ )
+ }
+ }
/**
* LiveData whose data is a map of grant category (either allowed or denied) to a list of
diff --git a/flags/flags.aconfig b/flags/flags.aconfig
index 2dd34e5ff..4f0f08938 100644
--- a/flags/flags.aconfig
+++ b/flags/flags.aconfig
@@ -47,6 +47,15 @@ flag {
}
flag {
+ name: "enhanced_confirmation_backport_enabled"
+ is_exported: true
+ namespace: "permissions"
+ description: "Flag to backport enhanced confirmation in permission mainline to T and U."
+ bug: "347876543"
+ is_fixed_read_only: true
+}
+
+flag {
name: "enable_coarse_fine_location_prompt_for_aaos"
is_exported: true
namespace: "permissions"
diff --git a/tests/cts/permissionui/Android.bp b/tests/cts/permissionui/Android.bp
index c1ec017ff..72624f5e2 100644
--- a/tests/cts/permissionui/Android.bp
+++ b/tests/cts/permissionui/Android.bp
@@ -44,6 +44,7 @@ android_test {
"platform-test-annotations",
"android.content.pm.flags-aconfig-java-export",
"android.permission.flags-aconfig-java-export",
+ "com.android.permission.flags-aconfig-java-export",
"Harrier",
],
data: [
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
index fdc13b3af..7e3f7f8dc 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
@@ -1102,6 +1102,21 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
}
}
+ @Suppress("DEPRECATION")
+ protected fun startManageAppPermissionsActivity() {
+ doAndWaitForWindowTransition {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ }
+ )
+ }
+ }
+ }
+
/** Starts activity with intent [ACTION_REVIEW_APP_DATA_SHARING_UPDATES]. */
fun startAppDataSharingUpdatesActivity() {
doAndWaitForWindowTransition {
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationBackportTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationBackportTest.kt
new file mode 100644
index 000000000..f38f678e9
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationBackportTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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 android.permissionui.cts
+
+import android.Manifest.permission_group.SMS
+import android.os.Build
+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.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.modules.utils.build.SdkLevel
+import com.android.permission.flags.Flags
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+/** Enhanced Confirmation Backport UI tests. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+class EnhancedConfirmationBackportTest : BaseUsePermissionTest() {
+
+ @JvmField
+ @Rule
+ val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
+ @Before
+ fun setup() {
+ assumeFalse(isAutomotive)
+ assumeFalse(isTv)
+ assumeFalse(isWatch)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_BACKPORT_ENABLED)
+ @Test
+ fun installDownloadedFile_clickAppPermissions_clickAllowRestrictedSettings_clickSMSPermGroup_clickAllowed() {
+ installPackageWithInstallSourceAndNoMetadataFromDownloadedFile(APP_APK_NAME_LATEST)
+
+ startManageAppPermissionsActivity()
+ waitFindObject(By.descContains(MORE_OPTIONS)).clickAndWait(
+ Until.newWindow(),
+ BasePermissionTest.TIMEOUT_MILLIS
+ )
+
+ if (!SdkLevel.isAtLeastV()) {
+ waitFindObject(By.text(ALLOW_RESTRICTED_SETTINGS)).click()
+
+ pressBack()
+
+ navigateToIndividualPermissionSetting(SMS)
+
+ assertAllowButtonIsEnabledAndClickAndChecked()
+
+ pressBack()
+ } else {
+ findView(By.text(ALLOW_RESTRICTED_SETTINGS), false)
+ }
+
+ pressBack()
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_BACKPORT_ENABLED)
+ @Test
+ fun installFromLocalFile_clickAppPermissions_clickAllowRestrictedSettings_clickSMSPermGroup_clickAllowed() {
+ installPackageWithInstallSourceAndNoMetadataFromLocalFile(APP_APK_NAME_LATEST)
+
+ startManageAppPermissionsActivity()
+ waitFindObject(By.descContains(MORE_OPTIONS)).click()
+
+ if (!SdkLevel.isAtLeastV()) {
+ waitFindObject(By.text(ALLOW_RESTRICTED_SETTINGS)).click()
+
+ pressBack()
+
+ navigateToIndividualPermissionSetting(SMS)
+
+ assertAllowButtonIsEnabledAndClickAndChecked()
+
+ pressBack()
+ } else {
+ findView(By.text(ALLOW_RESTRICTED_SETTINGS), false)
+ }
+
+ pressBack()
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @RequiresFlagsDisabled(Flags.FLAG_ENHANCED_CONFIRMATION_BACKPORT_ENABLED)
+ @Test
+ fun installDownloadedFile_clickAppPermissions_noAllowRestrictedSettings() {
+ installPackageWithInstallSourceAndNoMetadataFromDownloadedFile(APP_APK_NAME_LATEST)
+
+ startManageAppPermissionsActivity()
+ waitFindObject(By.descContains(MORE_OPTIONS)).clickAndWait(
+ Until.newWindow(),
+ BasePermissionTest.TIMEOUT_MILLIS
+ )
+
+ findView(By.text(ALLOW_RESTRICTED_SETTINGS), false)
+
+ pressBack()
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @RequiresFlagsDisabled(Flags.FLAG_ENHANCED_CONFIRMATION_BACKPORT_ENABLED)
+ @Test
+ fun installFromLocalFile_clickAppPermissions_noAllowRestrictedSettings() {
+ installPackageWithInstallSourceAndNoMetadataFromLocalFile(APP_APK_NAME_LATEST)
+
+ startManageAppPermissionsActivity()
+ waitFindObject(By.descContains(MORE_OPTIONS)).click()
+
+ findView(By.text(ALLOW_RESTRICTED_SETTINGS), false)
+
+ pressBack()
+ }
+
+ private fun assertAllowButtonIsEnabledAndClickAndChecked() {
+ waitFindObject(By.res(ALLOW_RADIO_BUTTON).enabled(true).checked(false))
+ .click()
+ waitFindObject(By.res(ALLOW_RADIO_BUTTON).checked(true))
+ }
+
+ companion object {
+ private const val MORE_OPTIONS = "More options"
+ private const val ALLOW_RESTRICTED_SETTINGS = "Allow restricted settings"
+ }
+}