diff options
author | 2024-06-21 22:07:02 +0000 | |
---|---|---|
committer | 2024-07-24 00:34:34 +0000 | |
commit | ee17b3ec38f649354ba3d131d6490dedf6d7a22f (patch) | |
tree | a1c8798aae3d99a84ccdd490f9d1cf952d5f6dd3 | |
parent | 1174eab1d2e09ff9516baaa3db83d42b6410e610 (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
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" + } +} |