diff options
author | 2019-11-19 10:08:03 -0800 | |
---|---|---|
committer | 2019-11-19 16:11:13 -0800 | |
commit | ef775a11b28a499ef1d474e697caa319f06f0591 (patch) | |
tree | d91039bd5136aa4470e207ca8c47aab22173d826 | |
parent | 59f71f0506abe36495e88e3b9397cd89c1a34f37 (diff) |
Add "Ask" radio button in AppPermission page
The new button signifies that the permission is denied but the app may
ask for the permission again. The existing "Deny" button now signifies
the denied with prejudice state which means apps can't ask anymore.
Test: PermissionsHostTest
Bug: 144389816
Change-Id: I60321e35ae5887442b6ce41ed0d55ec449b56b3b
6 files changed, 86 insertions, 30 deletions
diff --git a/PermissionController/res/layout/app_permission.xml b/PermissionController/res/layout/app_permission.xml index 2795a3420..a8306cb2d 100644 --- a/PermissionController/res/layout/app_permission.xml +++ b/PermissionController/res/layout/app_permission.xml @@ -62,6 +62,11 @@ style="@style/AppPermissionRadioButton" /> <RadioButton + android:id="@+id/ask_radio_button" + android:text="@string/app_permission_button_ask" + style="@style/AppPermissionRadioButton" /> + + <RadioButton android:id="@+id/deny_radio_button" android:text="@string/app_permission_button_deny" style="@style/AppPermissionRadioButton" /> diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml index d0fcc7bb6..e28972ac4 100644 --- a/PermissionController/res/values/strings.xml +++ b/PermissionController/res/values/strings.xml @@ -403,7 +403,10 @@ <!-- Title for the dialog button to allow a permission grant only when the app is in the foreground. [CHAR LIMIT=60] --> <string name="app_permission_button_allow_foreground">Allow only while using the app</string> - <!-- Title for the dialog button to deny a permission grant. [CHAR LIMIT=60] --> + <!-- Title for the dialog button to require an app to ask for a permission next time they need it. [CHAR LIMIT=60] --> + <string name="app_permission_button_ask">Ask every time</string> + + <!-- Title for the dialog button to deny with prejudice a permission grant. [CHAR LIMIT=60] --> <string name="app_permission_button_deny">Deny</string> <!-- Title for app permission [CHAR LIMIT=30] --> diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt index 9c3bb8a23..057f59991 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt @@ -92,4 +92,9 @@ data class LightAppPermGroup( val isBackgroundGranted = permissions.any { backgroundPermNames.contains(it.key) && it.value.grantedIncludingAppOp } + + /** + * Whether this App Permission Group's permissions are fixed by the user + */ + val isUserFixed = permissions.any { it.value.isUserFixed } }
\ No newline at end of file diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt index d8224af67..cce232c83 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt @@ -43,4 +43,6 @@ data class LightPermission( val isPolicyFixed = flags and PackageManager.FLAG_PERMISSION_POLICY_FIXED != 0 /** Whether this permission is fixed by the system */ val isSystemFixed = flags and PackageManager.FLAG_PERMISSION_SYSTEM_FIXED != 0 + /** Whether this permission is fixed by the system */ + val isUserFixed = flags and PackageManager.FLAG_PERMISSION_USER_FIXED != 0 }
\ No newline at end of file diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java index 3eaad5b76..f751f89e1 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java @@ -69,6 +69,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { private @NonNull RadioButton mAlwaysButton; private @NonNull RadioButton mForegroundOnlyButton; + private @NonNull RadioButton mAskButton; private @NonNull RadioButton mDenyButton; private @NonNull View mDivider; private @NonNull ViewGroup mWidgetFrame; @@ -177,6 +178,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { mAlwaysButton = root.requireViewById(R.id.allow_radio_button); mForegroundOnlyButton = root.requireViewById(R.id.foreground_only_radio_button); + mAskButton = root.requireViewById(R.id.ask_radio_button); mDenyButton = root.requireViewById(R.id.deny_radio_button); mDivider = root.requireViewById(R.id.two_target_divider); mWidgetFrame = root.requireViewById(R.id.widget_frame); @@ -217,25 +219,27 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { } mAlwaysButton.setOnClickListener((v) -> { - mViewModel.requestChange(true, this, ChangeTarget.CHANGE_BOTH); - getActivity().setResult(Activity.RESULT_OK, new Intent().putExtra( - AppPermissionActivity.EXTRA_RESULT_PERMISSION_INTERACTED, mPermGroupName)); + mViewModel.requestChange(true, false, this, ChangeTarget.CHANGE_BOTH); + setResult(); }); mForegroundOnlyButton.setOnClickListener((v) -> { - mViewModel.requestChange(true, this, ChangeTarget.CHANGE_FOREGROUND); - mViewModel.requestChange(false, this, ChangeTarget.CHANGE_BACKGROUND); - getActivity().setResult(Activity.RESULT_OK, new Intent().putExtra( - AppPermissionActivity.EXTRA_RESULT_PERMISSION_INTERACTED, mPermGroupName)); + mViewModel.requestChange(true, false, this, ChangeTarget.CHANGE_FOREGROUND); + mViewModel.requestChange(false, false, this, ChangeTarget.CHANGE_BACKGROUND); + setResult(); + }); + mAskButton.setOnClickListener((v) -> { + mViewModel.requestChange(false, false, this, ChangeTarget.CHANGE_BOTH); + setResult(); }); mDenyButton.setOnClickListener((v) -> { - mViewModel.requestChange(false, this, ChangeTarget.CHANGE_BOTH); - getActivity().setResult(Activity.RESULT_OK, new Intent().putExtra( - AppPermissionActivity.EXTRA_RESULT_PERMISSION_INTERACTED, mPermGroupName)); + mViewModel.requestChange(false, true, this, ChangeTarget.CHANGE_BOTH); + setResult(); }); setButtonState(mAlwaysButton, states.get(0), true); setButtonState(mForegroundOnlyButton, states.get(1), false); - setButtonState(mDenyButton, states.get(2), false); + setButtonState(mAskButton, states.get(2), false); + setButtonState(mDenyButton, states.get(3), false); if (mForegroundOnlyButton.getVisibility() == View.GONE) { mAlwaysButton.setText(getContext().getString(R.string.app_permission_button_allow)); @@ -246,6 +250,11 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { } + private void setResult() { + getActivity().setResult(Activity.RESULT_OK, new Intent().putExtra( + AppPermissionActivity.EXTRA_RESULT_PERMISSION_INTERACTED, mPermGroupName)); + } + private void setButtonState(RadioButton button, AppPermissionViewModel.ButtonState state, boolean requestGrant) { button.setChecked(state.isChecked()); @@ -253,8 +262,11 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { int visible = state.isShown() ? View.VISIBLE : View.GONE; button.setVisibility(visible); if (state.getCustomTarget() != null) { - button.setOnClickListener((v) -> mViewModel.requestChange(requestGrant, this, - state.getCustomTarget())); + button.setOnClickListener((v) -> { + mViewModel.requestChange(requestGrant, button == mDenyButton, this, + state.getCustomTarget()); + setResult(); + }); } } @@ -332,12 +344,15 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { * * @param changeTarget Whether background or foreground should be changed * @param messageId The Id of the string message to show + * @param userFixed Whether the permission state should be user fixed */ - void showDefaultDenyDialog(ChangeTarget changeTarget, @StringRes int messageId) { + void showDefaultDenyDialog(ChangeTarget changeTarget, @StringRes int messageId, + boolean userFixed) { Bundle args = new Bundle(); args.putInt(DefaultDenyDialog.MSG, messageId); args.putSerializable(DefaultDenyDialog.CHANGE_TARGET, changeTarget); + args.putBoolean(DefaultDenyDialog.USER_FIXED, userFixed); DefaultDenyDialog defaultDenyDialog = new DefaultDenyDialog(); defaultDenyDialog.setCancelable(true); @@ -350,13 +365,17 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { * A dialog warning the user that she/he is about to deny a permission that was granted by * default. * - * @see #showDefaultDenyDialog(ChangeTarget, int) + * @see #showDefaultDenyDialog(ChangeTarget, int, boolean) */ public static class DefaultDenyDialog extends DialogFragment { static final String MSG = DefaultDenyDialog.class.getName() + ".arg.msg"; static final String CHANGE_TARGET = DefaultDenyDialog.class.getName() + ".arg.changeTarget"; private static final String KEY = DefaultDenyDialog.class.getName() + ".arg.key"; + static final String USER_FIXED = DefaultDenyDialog.class.getName() + + ".arg.userFixed"; + + private boolean mFixed; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { @@ -368,7 +387,8 @@ public class AppPermissionFragment extends SettingsWithLargeHeader { .setPositiveButton(R.string.grant_dialog_button_deny_anyway, (DialogInterface dialog, int which) -> fragment.mViewModel.onDenyAnyWay((ChangeTarget) - getArguments().getSerializable(CHANGE_TARGET))); + getArguments().getSerializable(CHANGE_TARGET), + getArguments().getBoolean(USER_FIXED, false))); Dialog d = b.create(); d.setCanceledOnTouchOutside(true); return d; diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionViewModel.kt index eee6e45af..92a191a6c 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionViewModel.kt @@ -138,6 +138,7 @@ class AppPermissionViewModel( val allowedState = ButtonState() val foregroundState = ButtonState() + val askState = ButtonState() val deniedState = ButtonState() if (group.isForegroundGranted) { @@ -147,11 +148,16 @@ class AppPermissionViewModel( foregroundState.isChecked = true } } else { - deniedState.isChecked = true + if (group.isUserFixed || group.isPolicyFullyFixed || group.isSystemFixed) { + deniedState.isChecked = true + } else { + askState.isChecked = true + } } if (group.hasPermWithBackground && !group.hasBackgroundPerms) { allowedState.isShown = false + askState.customTarget = ChangeTarget.CHANGE_FOREGROUND deniedState.customTarget = ChangeTarget.CHANGE_FOREGROUND } else if (!group.hasPermWithBackground) { foregroundState.isShown = false @@ -161,6 +167,7 @@ class AppPermissionViewModel( !group.isForegroundGranted)) { allowedState.isEnabled = false foregroundState.isEnabled = false + askState.isEnabled = false deniedState.isEnabled = false val detailId = getDetailResIdForFixedByPolicyPermissionGroup(group, @@ -169,13 +176,13 @@ class AppPermissionViewModel( detailResIdLiveData.value = detailId to null } - value = listOf(allowedState, foregroundState, deniedState) + value = listOf(allowedState, foregroundState, askState, deniedState) showAdminSupportLiveData.value = admin return } else if (Utils.areGroupPermissionsIndividuallyControlled(app, permGroupName)) { val detailId = getIndividualPermissionDetailResId(group) detailResIdLiveData.value = detailId.first to detailId.second - value = listOf(allowedState, foregroundState, deniedState) + value = listOf(allowedState, foregroundState, askState, deniedState) return } @@ -211,7 +218,7 @@ class AppPermissionViewModel( } } detailResIdLiveData.value = null - value = listOf(allowedState, foregroundState, deniedState) + value = listOf(allowedState, foregroundState, askState, deniedState) } override fun onActive() { @@ -297,6 +304,7 @@ class AppPermissionViewModel( */ fun requestChange( requestGrant: Boolean, + userFixed: Boolean, fragment: AppPermissionFragment, changeTarget: ChangeTarget ) { @@ -316,7 +324,7 @@ class AppPermissionViewModel( val stateBefore = createPermissionSnapshot()!! if (shouldChangeForeground) { val runtimePermissionsGranted = group.areRuntimePermissionsGranted() - group.grantRuntimePermissions(false) + group.grantRuntimePermissions(userFixed) if (!runtimePermissionsGranted) { SafetyNetLogger.logPermissionToggled(group) @@ -325,7 +333,7 @@ class AppPermissionViewModel( if (shouldChangeBackground && group.backgroundPermissions != null) { val runtimePermissionsGranted = group.backgroundPermissions.areRuntimePermissionsGranted() - group.backgroundPermissions.grantRuntimePermissions(false) + group.backgroundPermissions.grantRuntimePermissions(userFixed) if (!runtimePermissionsGranted) { SafetyNetLogger.logPermissionToggled(group.backgroundPermissions) @@ -357,26 +365,39 @@ class AppPermissionViewModel( } if (showDefaultDenyDialog && !hasConfirmedRevoke && showGrantedByDefaultWarning) { - fragment.showDefaultDenyDialog(changeTarget, R.string.system_warning) + fragment.showDefaultDenyDialog(changeTarget, R.string.system_warning, userFixed) return } else if (showDefaultDenyDialog && !hasConfirmedRevoke) { - fragment.showDefaultDenyDialog(changeTarget, R.string.old_sdk_deny_warning) + fragment.showDefaultDenyDialog(changeTarget, R.string.old_sdk_deny_warning, + userFixed) return } else { val stateBefore = createPermissionSnapshot()!! if (shouldChangeForeground && group.areRuntimePermissionsGranted()) { - group.revokeRuntimePermissions(false) + group.revokeRuntimePermissions(userFixed) SafetyNetLogger.logPermissionToggled(group) } if (shouldChangeBackground && group.backgroundPermissions != null && group.backgroundPermissions.areRuntimePermissionsGranted()) { - group.backgroundPermissions.revokeRuntimePermissions(false) + group.backgroundPermissions.revokeRuntimePermissions(userFixed) SafetyNetLogger.logPermissionToggled(group.backgroundPermissions) } + if (userFixed && !group.isUserFixed) { + group.revokeRuntimePermissions(true) + if (group.backgroundPermissions != null) { + group.backgroundPermissions.revokeRuntimePermissions(true) + } + } + if (!userFixed && group.isUserFixed) { + group.revokeRuntimePermissions(false) + if (group.backgroundPermissions != null) { + group.backgroundPermissions.revokeRuntimePermissions(false) + } + } logPermissionChanges(stateBefore) } } @@ -389,13 +410,13 @@ class AppPermissionViewModel( * @param changeTarget whether to change foreground, background, or both. * */ - fun onDenyAnyWay(changeTarget: ChangeTarget) { + fun onDenyAnyWay(changeTarget: ChangeTarget, userFixed: Boolean) { val group = appPermissionGroup ?: return var hasDefaultPermissions = false val stateBefore = createPermissionSnapshot() if (changeTarget andValue ChangeTarget.CHANGE_FOREGROUND != 0) { val runtimePermissionsGranted = group.areRuntimePermissionsGranted() - group.revokeRuntimePermissions(false) + group.revokeRuntimePermissions(userFixed) if (runtimePermissionsGranted) { SafetyNetLogger.logPermissionToggled(group) @@ -406,7 +427,7 @@ class AppPermissionViewModel( group.backgroundPermissions != null) { val runtimePermissionsGranted = group.backgroundPermissions.areRuntimePermissionsGranted() - group.backgroundPermissions.revokeRuntimePermissions(false) + group.backgroundPermissions.revokeRuntimePermissions(userFixed) if (runtimePermissionsGranted) { SafetyNetLogger.logPermissionToggled(group.backgroundPermissions) |