summaryrefslogtreecommitdiffstats
path: root/src/com/android/packageinstaller/permission/ui
diff options
context:
space:
mode:
authorSvet Ganov <svetoslavganov@google.com>2015-09-27 08:10:39 -0700
committerSvet Ganov <svetoslavganov@google.com>2015-12-01 19:55:08 -0800
commitbf7316751f0c73b435b693fd20b0c9b2fa973e85 (patch)
tree5f372a0d0e8644921cf40905c623b4b11c88e03e /src/com/android/packageinstaller/permission/ui
parente3ba0f72cf3a38d5f196b10f976dfe4c5dd5dff5 (diff)
downloadandroid_packages_apps_PackageInstaller-bf7316751f0c73b435b693fd20b0c9b2fa973e85.tar.gz
android_packages_apps_PackageInstaller-bf7316751f0c73b435b693fd20b0c9b2fa973e85.tar.bz2
android_packages_apps_PackageInstaller-bf7316751f0c73b435b693fd20b0c9b2fa973e85.zip
Add optional permission review for legacy apps - installer
Change-Id: Ifc88b2fa259d2d22bea6b5500cded2714ad4da85
Diffstat (limited to 'src/com/android/packageinstaller/permission/ui')
-rw-r--r--src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java63
-rw-r--r--src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java397
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java213
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java9
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java15
5 files changed, 632 insertions, 65 deletions
diff --git a/src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java b/src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java
new file mode 100644
index 00000000..fb562e2a
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/ConfirmActionDialogFragment.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 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 com.android.packageinstaller.permission.ui;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import com.android.packageinstaller.R;
+
+public final class ConfirmActionDialogFragment extends DialogFragment {
+ public static final String ARG_MESSAGE = "MESSAGE";
+ public static final String ARG_ACTION = "ACTION";
+
+ public static interface OnActionConfirmedListener {
+ public void onActionConfirmed(String action);
+ }
+
+ public static ConfirmActionDialogFragment newInstance(CharSequence message, String action) {
+ Bundle arguments = new Bundle();
+ arguments.putCharSequence(ARG_MESSAGE, message);
+ arguments.putString(ARG_ACTION, action);
+ ConfirmActionDialogFragment fragment = new ConfirmActionDialogFragment();
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle bundle) {
+ return new AlertDialog.Builder(getContext())
+ .setMessage(getArguments().getString(ARG_MESSAGE))
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.grant_dialog_button_deny,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Activity activity = getActivity();
+ if (activity instanceof OnActionConfirmedListener) {
+ String groupName = getArguments().getString(ARG_ACTION);
+ ((OnActionConfirmedListener) activity)
+ .onActionConfirmed(groupName);
+ }
+ }
+ })
+ .create();
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java
new file mode 100644
index 00000000..b872983d
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/ReviewPermissionsActivity.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2015 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 com.android.packageinstaller.permission.ui;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.preference.TwoStatePreference;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.utils.Utils;
+import com.android.packageinstaller.permission.ui.ConfirmActionDialogFragment.OnActionConfirmedListener;
+
+import java.util.List;
+
+public final class ReviewPermissionsActivity extends Activity
+ implements OnActionConfirmedListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ PackageInfo packageInfo = getTargetPackageInfo();
+ if (packageInfo == null) {
+ finish();
+ return;
+ }
+
+ setContentView(R.layout.review_permissions);
+ if (getFragmentManager().findFragmentById(R.id.preferences_frame) == null) {
+ getFragmentManager().beginTransaction().add(R.id.preferences_frame,
+ ReviewPermissionsFragment.newInstance(packageInfo)).commit();
+ }
+ }
+
+ @Override
+ public void onActionConfirmed(String action) {
+ Fragment fragment = getFragmentManager().findFragmentById(R.id.preferences_frame);
+ if (fragment instanceof OnActionConfirmedListener) {
+ ((OnActionConfirmedListener) fragment).onActionConfirmed(action);
+ }
+ }
+
+ private PackageInfo getTargetPackageInfo() {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ try {
+ return getPackageManager().getPackageInfo(packageName,
+ PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ public static final class ReviewPermissionsFragment extends PreferenceFragment
+ implements View.OnClickListener, Preference.OnPreferenceChangeListener,
+ ConfirmActionDialogFragment.OnActionConfirmedListener {
+ public static final String EXTRA_PACKAGE_INFO =
+ "com.android.packageinstaller.permission.ui.extra.PACKAGE_INFO";
+
+ private AppPermissions mAppPermissions;
+
+ private Button mContinueButton;
+ private Button mCancelButton;
+
+ private PreferenceCategory mNewPermissionsCategory;
+
+ private boolean mHasConfirmedRevoke;
+
+ public static ReviewPermissionsFragment newInstance(PackageInfo packageInfo) {
+ Bundle arguments = new Bundle();
+ arguments.putParcelable(ReviewPermissionsFragment.EXTRA_PACKAGE_INFO, packageInfo);
+ ReviewPermissionsFragment instance = new ReviewPermissionsFragment();
+ instance.setArguments(arguments);
+ instance.setRetainInstance(true);
+ return instance;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ PackageInfo packageInfo = getArguments().getParcelable(EXTRA_PACKAGE_INFO);
+ if (packageInfo == null) {
+ getActivity().finish();
+ return;
+ }
+
+ mAppPermissions = new AppPermissions(getActivity(), packageInfo, null, false,
+ new Runnable() {
+ @Override
+ public void run() {
+ getActivity().finish();
+ }
+ });
+
+ if (mAppPermissions.getPermissionGroups().isEmpty()) {
+ getActivity().finish();
+ return;
+ }
+
+ boolean reviewRequired= false;
+ for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ if (group.isReviewRequired()) {
+ reviewRequired = true;
+ break;
+ }
+ }
+
+ if (!reviewRequired) {
+ getActivity().finish();
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindUi();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ loadPreferences();
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == mContinueButton) {
+ confirmPermissionsReview();
+ executeCallback(true);
+ } else if (view == mCancelButton) {
+ executeCallback(false);
+ getActivity().setResult(Activity.RESULT_CANCELED);
+ }
+ getActivity().finish();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (mHasConfirmedRevoke) {
+ return true;
+ }
+ if (preference instanceof SwitchPreference) {
+ SwitchPreference switchPreference = (SwitchPreference) preference;
+ if (switchPreference.isChecked()) {
+ showWarnRevokeDialog(switchPreference.getKey());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onActionConfirmed(String action) {
+ Preference preference = getPreferenceManager().findPreference(action);
+ if (preference instanceof SwitchPreference) {
+ SwitchPreference switchPreference = (SwitchPreference) preference;
+ switchPreference.setChecked(false);
+ mHasConfirmedRevoke = true;
+ }
+ }
+
+ private void showWarnRevokeDialog(final String groupName) {
+ DialogFragment fragment = ConfirmActionDialogFragment.newInstance(
+ getString(R.string.old_sdk_deny_warning), groupName);
+ fragment.show(getFragmentManager(), fragment.getClass().getName());
+ }
+
+ private void confirmPermissionsReview() {
+ PreferenceGroup preferenceGroup = mNewPermissionsCategory != null
+ ? mNewPermissionsCategory : getPreferenceScreen();
+
+ final int preferenceCount = preferenceGroup.getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ Preference preference = preferenceGroup.getPreference(i);
+ if (preference instanceof TwoStatePreference) {
+ TwoStatePreference twoStatePreference = (TwoStatePreference) preference;
+ String groupName = preference.getKey();
+ AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
+ if (twoStatePreference.isChecked()) {
+ group.grantRuntimePermissions(false);
+ } else {
+ group.revokeRuntimePermissions(false);
+ }
+ group.resetReviewRequired();
+ }
+ }
+ }
+
+ private void bindUi() {
+ Activity activity = getActivity();
+
+ // Set icon
+ Drawable icon = mAppPermissions.getPackageInfo().applicationInfo.loadIcon(
+ activity.getPackageManager());
+ ImageView iconView = (ImageView) activity.findViewById(R.id.app_icon);
+ iconView.setImageDrawable(icon);
+
+ // Set message
+ String appLabel = mAppPermissions.getAppLabel().toString();
+ final int labelTemplateResId = isPackageUpdated()
+ ? R.string.permission_review_title_template_update
+ : R.string.permission_review_title_template_install;
+ SpannableString message = new SpannableString(getString(labelTemplateResId, appLabel));
+ // Set the permission message as the title so it can be announced.
+ activity.setTitle(message);
+
+ // Color the app name.
+ final int appLabelStart = message.toString().indexOf(appLabel, 0);
+ final int appLabelLength = appLabel.length();
+
+ TypedValue typedValue = new TypedValue();
+ activity.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+ final int color = activity.getColor(typedValue.resourceId);
+
+ message.setSpan(new ForegroundColorSpan(color), appLabelStart,
+ appLabelStart + appLabelLength, 0);
+ TextView permissionsMessageView = (TextView) activity.findViewById(
+ R.id.permissions_message);
+ permissionsMessageView.setText(message);
+
+
+ mContinueButton = (Button) getActivity().findViewById(R.id.continue_button);
+ mContinueButton.setOnClickListener(this);
+
+ mCancelButton = (Button) getActivity().findViewById(R.id.cancel_button);
+ mCancelButton.setOnClickListener(this);
+ }
+
+ private void loadPreferences() {
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ } else {
+ screen.removeAll();
+ }
+
+ PreferenceGroup currentPermissionsCategory = null;
+ PreferenceGroup oldNewPermissionsCategory = mNewPermissionsCategory;
+ mNewPermissionsCategory = null;
+
+ final boolean isPackageUpdated = isPackageUpdated();
+
+ for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ if (!Utils.shouldShowPermission(group,
+ mAppPermissions.getPackageInfo().packageName)) {
+ continue;
+ }
+
+ // TODO: Sort permissions - platform first then third-party ones
+
+ final SwitchPreference preference;
+ Preference cachedPreference = oldNewPermissionsCategory != null
+ ? oldNewPermissionsCategory.findPreference(group.getName()) : null;
+ if (cachedPreference instanceof SwitchPreference) {
+ preference = (SwitchPreference) cachedPreference;
+ } else {
+ preference = new SwitchPreference(getActivity());
+
+ // We update permission grants based on the final preference states
+ if (group.isReviewRequired()) {
+ // If review is required use granted as default
+ preference.setChecked(true);
+ } else {
+ // If review not required use the current grant state as default
+ preference.setChecked(group.areRuntimePermissionsGranted());
+ }
+
+ preference.setKey(group.getName());
+ Drawable icon = Utils.loadDrawable(getActivity().getPackageManager(),
+ group.getIconPkg(), group.getIconResId());
+ preference.setIcon(Utils.applyTint(getContext(), icon,
+ android.R.attr.colorControlNormal));
+ preference.setTitle(group.getLabel());
+ preference.setSummary(group.getDescription());
+ preference.setPersistent(false);
+
+ preference.setOnPreferenceChangeListener(this);
+ }
+
+ // Mutable state
+ if (group.isPolicyFixed()) {
+ preference.setEnabled(false);
+ preference.setSummary(getString(
+ R.string.permission_summary_enforced_by_policy));
+ } else {
+ preference.setEnabled(true);
+ }
+
+ if (group.isReviewRequired()) {
+ if (!isPackageUpdated) {
+ screen.addPreference(preference);
+ } else {
+ if (mNewPermissionsCategory == null) {
+ mNewPermissionsCategory = new PreferenceCategory(getActivity());
+ mNewPermissionsCategory.setTitle(R.string.new_permissions_category);
+ mNewPermissionsCategory.setOrder(1);
+ screen.addPreference(mNewPermissionsCategory);
+ }
+ mNewPermissionsCategory.addPreference(preference);
+ }
+ } else {
+ if (currentPermissionsCategory == null) {
+ currentPermissionsCategory = new PreferenceCategory(getActivity());
+ currentPermissionsCategory.setTitle(R.string.current_permissions_category);
+ currentPermissionsCategory.setOrder(2);
+ screen.addPreference(currentPermissionsCategory);
+ }
+ currentPermissionsCategory.addPreference(preference);
+ }
+ }
+ }
+
+ private boolean isPackageUpdated() {
+ List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups();
+ final int groupCount = groups.size();
+ for (int i = 0; i < groupCount; i++) {
+ AppPermissionGroup group = groups.get(i);
+ if (!group.isReviewRequired()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void executeCallback(boolean success) {
+ Activity activity = getActivity();
+ if (success) {
+ IntentSender intent = activity.getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
+ if (intent != null) {
+ try {
+ int flagMask = 0;
+ int flagValues = 0;
+ if (activity.getIntent().getBooleanExtra(
+ Intent.EXTRA_RESULT_NEEDED, false)) {
+ flagMask = Intent.FLAG_ACTIVITY_FORWARD_RESULT;
+ flagValues = Intent.FLAG_ACTIVITY_FORWARD_RESULT;
+ }
+ activity.startIntentSenderForResult(intent, -1, null,
+ flagMask, flagValues, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
+ return;
+ }
+ }
+ RemoteCallback callback = activity.getIntent().getParcelableExtra(
+ Intent.EXTRA_REMOTE_CALLBACK);
+ if (callback != null) {
+ Bundle result = new Bundle();
+ result.putBoolean(Intent.EXTRA_RETURN_RESULT, success);
+ callback.sendResult(result);
+ }
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
index d4910128..2c0a123b 100644
--- a/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
@@ -16,8 +16,10 @@
package com.android.packageinstaller.permission.ui.television;
+import android.Manifest;
import android.app.ActionBar;
import android.app.AlertDialog;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -28,9 +30,12 @@ import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup;
@@ -38,6 +43,8 @@ import android.util.Log;
import android.view.MenuItem;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissions;
import com.android.packageinstaller.permission.utils.Utils;
import java.util.ArrayList;
@@ -50,6 +57,10 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
private static final String KEY_OTHER = "other_perms";
+ private PackageInfo mPackageInfo;
+
+ private AppPermissions mAppPermissions;
+
public static AllAppPermissionsFragment newInstance(String packageName) {
AllAppPermissionsFragment instance = new AllAppPermissionsFragment();
Bundle arguments = new Bundle();
@@ -67,6 +78,22 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
ab.setTitle(R.string.all_permissions);
ab.setDisplayHomeAsUpEnabled(true);
}
+
+ String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ try {
+ mPackageInfo = getActivity().getPackageManager().getPackageInfo(pkg,
+ PackageManager.GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
+ getActivity().finish();
+ }
+
+ mAppPermissions = new AppPermissions(getActivity(), mPackageInfo, null, false,
+ new Runnable() {
+ @Override
+ public void run() {
+ getActivity().finish();
+ }
+ });
}
@Override
@@ -86,62 +113,64 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
return super.onOptionsItemSelected(item);
}
- private void updateUi() {
- if (getPreferenceScreen() != null) {
- getPreferenceScreen().removeAll();
- }
- addPreferencesFromResource(R.xml.all_permissions);
+ private PreferenceGroup getOtherGroup() {
PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER);
+ if (otherGroup == null) {
+ otherGroup = new PreferenceCategory(getPreferenceManager().getContext());
+ otherGroup.setKey(KEY_OTHER);
+ otherGroup.setTitle(getString(R.string.other_permissions));
+ getPreferenceScreen().addPreference(otherGroup);
+ }
+ return otherGroup;
+ }
+
+ private void updateUi() {
+ getPreferenceScreen().removeAll();
+
ArrayList<Preference> prefs = new ArrayList<>(); // Used for sorting.
- prefs.add(otherGroup);
- String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
- otherGroup.removeAll();
- PackageManager pm = getContext().getPackageManager();
+ PackageManager pm = getActivity().getPackageManager();
- try {
- PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
-
- ApplicationInfo appInfo = info.applicationInfo;
- final Drawable icon = appInfo.loadIcon(pm);
- final CharSequence label = appInfo.loadLabel(pm);
- Intent infoIntent = null;
- if (!getActivity().getIntent().getBooleanExtra(
- AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) {
- infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
- .setData(Uri.fromParts("package", pkg, null));
- }
- setHeader(icon, label, infoIntent);
-
- if (info.requestedPermissions != null) {
- for (int i = 0; i < info.requestedPermissions.length; i++) {
- PermissionInfo perm;
- try {
- perm = pm.getPermissionInfo(info.requestedPermissions[i], 0);
- } catch (NameNotFoundException e) {
- Log.e(LOG_TAG,
- "Can't get permission info for " + info.requestedPermissions[i], e);
- continue;
- }
+ ApplicationInfo appInfo = mPackageInfo.applicationInfo;
+ final Drawable icon = appInfo.loadIcon(pm);
+ final CharSequence label = appInfo.loadLabel(pm);
+ Intent infoIntent = null;
+ if (!getActivity().getIntent().getBooleanExtra(
+ AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) {
+ infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ .setData(Uri.fromParts("package", mPackageInfo.packageName, null));
+ }
+ setHeader(icon, label, infoIntent);
- if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
- || (perm.flags & PermissionInfo.FLAG_HIDDEN) != 0) {
- continue;
- }
+ if (mPackageInfo.requestedPermissions != null) {
+ for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
+ PermissionInfo perm;
+ try {
+ perm = pm.getPermissionInfo(mPackageInfo.requestedPermissions[i], 0);
+ } catch (NameNotFoundException e) {
+ Log.e(LOG_TAG, "Can't get permission info for "
+ + mPackageInfo.requestedPermissions[i], e);
+ continue;
+ }
+
+ if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (perm.flags & PermissionInfo.FLAG_HIDDEN) != 0) {
+ continue;
+ }
- if (perm.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
- PermissionGroupInfo group = getGroup(perm.group, pm);
- PreferenceGroup pref =
- findOrCreate(group != null ? group : perm, pm, prefs);
- pref.addPreference(getPreference(perm, group, pm));
- } else if (perm.protectionLevel == PermissionInfo.PROTECTION_NORMAL) {
- PermissionGroupInfo group = getGroup(perm.group, pm);
- otherGroup.addPreference(getPreference(perm, group, pm));
+ PermissionGroupInfo group = getGroup(perm.group, pm);
+ if (perm.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
+ PreferenceGroup pref = findOrCreate(group != null ? group : perm, pm, prefs);
+ pref.addPreference(getPreference(perm, group));
+ } else if (perm.protectionLevel == PermissionInfo.PROTECTION_NORMAL) {
+ PreferenceGroup otherGroup = getOtherGroup();
+ if (prefs.indexOf(otherGroup) < 0) {
+ prefs.add(otherGroup);
}
+ getOtherGroup().addPreference(getPreference(perm, group));
}
}
- } catch (NameNotFoundException e) {
- Log.e(LOG_TAG, "Problem getting package info for " + pkg, e);
}
+
// Sort an ArrayList of the groups and then set the order from the sorting.
Collections.sort(prefs, new Comparator<Preference>() {
@Override
@@ -176,7 +205,7 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
ArrayList<Preference> prefs) {
PreferenceGroup pref = (PreferenceGroup) findPreference(group.name);
if (pref == null) {
- pref = new PreferenceCategory(getContext());
+ pref = new PreferenceCategory(getActivity());
pref.setKey(group.name);
pref.setLayoutResource(R.layout.preference_category_material);
pref.setTitle(group.loadLabel(pm));
@@ -186,26 +215,57 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
return pref;
}
- private Preference getPreference(PermissionInfo perm, PermissionGroupInfo group,
- PackageManager pm) {
- Preference pref = new Preference(getContext());
- pref.setLayoutResource(R.layout.preference_permissions);
- Drawable icon = null;
- if (perm.icon != 0) {
- icon = perm.loadIcon(pm);
- } else if (group != null && group.icon != 0) {
- icon = group.loadIcon(pm);
+ private Preference getPreference(final PermissionInfo perm, final PermissionGroupInfo group) {
+ if (isMutableGranularPermission(perm.name)) {
+ return getMutablePreference(perm, group);
} else {
- icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
+ return getImmutablePreference(perm, group);
}
- pref.setIcon(Utils.applyTint(getContext(), icon, android.R.attr.colorControlNormal));
+ }
+
+ private Preference getMutablePreference(final PermissionInfo perm, PermissionGroupInfo group) {
+ final AppPermissionGroup permGroup = mAppPermissions.getPermissionGroup(group.name);
+ final String[] filterPermissions = new String[]{perm.name};
+
+ // TODO: No hardcoded layouts
+ SwitchPreference pref = new SwitchPreference(getPreferenceManager().getContext());
+ pref.setLayoutResource(R.layout.preference_permissions);
+ pref.setChecked(permGroup.areRuntimePermissionsGranted(filterPermissions));
+ pref.setIcon(getTintedPermissionIcon(getActivity(), perm, group));
+ pref.setTitle(perm.loadLabel(getActivity().getPackageManager()));
+ pref.setPersistent(false);
+
+ pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object value) {
+ if (value == Boolean.TRUE) {
+ permGroup.grantRuntimePermissions(false, filterPermissions);
+ } else {
+ permGroup.revokeRuntimePermissions(false, filterPermissions);
+ }
+ return true;
+ }
+ });
+
+ return pref;
+ }
+
+ private Preference getImmutablePreference(final PermissionInfo perm,
+ PermissionGroupInfo group) {
+ final PackageManager pm = getActivity().getPackageManager();
+
+ // TODO: No hardcoded layouts
+ Preference pref = new Preference(getActivity());
+ pref.setLayoutResource(R.layout.preference_permissions);
+ pref.setIcon(getTintedPermissionIcon(getActivity(), perm, group));
pref.setTitle(perm.loadLabel(pm));
- final CharSequence desc = perm.loadDescription(pm);
+ pref.setPersistent(false);
+
pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- new AlertDialog.Builder(getContext())
- .setMessage(desc)
+ new AlertDialog.Builder(getActivity())
+ .setMessage(perm.loadDescription(pm))
.setPositiveButton(android.R.string.ok, null)
.show();
return true;
@@ -214,4 +274,33 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
return pref;
}
+
+ private static Drawable getTintedPermissionIcon(Context context, PermissionInfo perm,
+ PermissionGroupInfo group) {
+ final Drawable icon;
+ if (perm.icon != 0) {
+ icon = perm.loadIcon(context.getPackageManager());
+ } else if (group != null && group.icon != 0) {
+ icon = group.loadIcon(context.getPackageManager());
+ } else {
+ icon = context.getDrawable(R.drawable.ic_perm_device_info);
+ }
+ return Utils.applyTint(context, icon, android.R.attr.colorControlNormal);
+ }
+
+ private static boolean isMutableGranularPermission(String name) {
+ if (!Build.PERMISSIONS_REVIEW_REQUIRED) {
+ return false;
+ }
+ switch (name) {
+ case Manifest.permission.READ_CONTACTS:
+ case Manifest.permission.WRITE_CONTACTS:
+ case Manifest.permission.READ_SMS:
+ case Manifest.permission.READ_CALL_LOG:
+ case Manifest.permission.CALL_PHONE: {
+ return true;
+ }
+ }
+ return false;
+ }
} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
index 42a2661c..52a6cbec 100644
--- a/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
@@ -109,6 +109,15 @@ public final class AppPermissionsFragment extends SettingsWithHeader
getActivity().finish();
}
});
+
+ if (mAppPermissions.isReviewRequired()) {
+ Intent intent = new Intent(getActivity(), ReviewPermissionsActivity.class);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ startActivity(intent);
+ getActivity().finish();
+ return;
+ }
+
loadPreferences();
}
diff --git a/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
index 0f240bef..f286aba0 100644
--- a/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
@@ -271,7 +271,8 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
@Override
public boolean onPreferenceClick(Preference preference) {
SystemAppsFragment frag = new SystemAppsFragment();
- setPermissionName(frag, getArguments().getString(Intent.EXTRA_PERMISSION_NAME));
+ setPermissionName(frag, getArguments().getString(
+ Intent.EXTRA_PERMISSION_NAME));
frag.setTargetFragment(PermissionAppsFragment.this, 0);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, frag)
@@ -327,13 +328,21 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple
return false;
}
- addToggledGroup(app.getPackageName(), app.getPermissionGroup());
-
if (LocationUtils.isLocationGroupAndProvider(mPermissionApps.getGroupName(),
app.getPackageName())) {
LocationUtils.showLocationDialog(getContext(), app.getLabel());
return false;
}
+
+ addToggledGroup(app.getPackageName(), app.getPermissionGroup());
+
+ if (app.isReviewRequired()) {
+ Intent intent = new Intent(getActivity(), ReviewPermissionsActivity.class);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, app.getPackageName());
+ startActivity(intent);
+ return false;
+ }
+
if (newValue == Boolean.TRUE) {
app.grantRuntimePermissions();
} else {