summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Severson <evanseverson@google.com> 2019-11-19 10:08:03 -0800
committer Evan Severson <evanseverson@google.com> 2019-11-19 16:11:13 -0800
commitef775a11b28a499ef1d474e697caa319f06f0591 (patch)
treed91039bd5136aa4470e207ca8c47aab22173d826
parent59f71f0506abe36495e88e3b9397cd89c1a34f37 (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
-rw-r--r--PermissionController/res/layout/app_permission.xml5
-rw-r--r--PermissionController/res/values/strings.xml5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionViewModel.kt47
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)