summaryrefslogtreecommitdiffstats
path: root/src/com/android/packageinstaller
diff options
context:
space:
mode:
authorSvet Ganov <svetoslavganov@google.com>2015-03-22 18:49:22 -0700
committerSvetoslav <svetoslavganov@google.com>2015-03-24 20:18:16 -0700
commit72b68774632f03289dc02d0e3dada06e9c984fd3 (patch)
treec427d0d5841da4391216b22728223508c0b49dd6 /src/com/android/packageinstaller
parent3c99a2b334eb00b6cfa078a9e9ed2d6a151bde46 (diff)
downloadandroid_packages_apps_PackageInstaller-72b68774632f03289dc02d0e3dada06e9c984fd3.tar.gz
android_packages_apps_PackageInstaller-72b68774632f03289dc02d0e3dada06e9c984fd3.tar.bz2
android_packages_apps_PackageInstaller-72b68774632f03289dc02d0e3dada06e9c984fd3.zip
Initial version of the grant permission UI.
Change-Id: Ieb311d29d122cfce130ae1a26889dd7794548833
Diffstat (limited to 'src/com/android/packageinstaller')
-rw-r--r--src/com/android/packageinstaller/permission/AppPermissions.java293
-rw-r--r--src/com/android/packageinstaller/permission/GrantPermissionFragment.java109
-rw-r--r--src/com/android/packageinstaller/permission/GrantPermissionsActivity.java246
-rw-r--r--src/com/android/packageinstaller/permission/ManagePermissionsActivity.java41
-rw-r--r--src/com/android/packageinstaller/permission/ManagePermissionsFragment.java128
5 files changed, 817 insertions, 0 deletions
diff --git a/src/com/android/packageinstaller/permission/AppPermissions.java b/src/com/android/packageinstaller/permission/AppPermissions.java
new file mode 100644
index 00000000..658accc1
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/AppPermissions.java
@@ -0,0 +1,293 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class AppPermissions {
+ private static final String LOG_TAG = "AppPermissions";
+
+ private final ArrayMap<String, PermissionGroup> mGroups = new ArrayMap<>();
+
+ private final Context mContext;
+
+ private final PackageInfo mPackageInfo;
+
+ private final String[] mFilterPermissions;
+
+ private final CharSequence mAppLabel;
+
+ public AppPermissions(Context context, PackageInfo packageInfo, String[] permissions) {
+ mContext = context;
+ mPackageInfo = packageInfo;
+ mFilterPermissions = permissions;
+ mAppLabel = packageInfo.applicationInfo.loadLabel(context.getPackageManager());
+ loadPermissionGroups();
+ }
+
+ public void refresh() {
+ loadPermissionGroups();
+ }
+
+ public CharSequence getAppLabel() {
+ return mAppLabel;
+ }
+
+ public PermissionGroup getPermissionGroup(String name) {
+ return mGroups.get(name);
+ }
+
+ public List<PermissionGroup> getPermissionGroups() {
+ return new ArrayList<>(mGroups.values());
+ }
+
+ private void loadPermissionGroups() {
+ mGroups.clear();
+
+ final boolean appSupportsRuntimePermissions = mPackageInfo.applicationInfo.targetSdkVersion
+ > Build.VERSION_CODES.LOLLIPOP_MR1;
+
+ for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
+ String requestedPerm = mPackageInfo.requestedPermissions[i];
+
+ final PermissionInfo permInfo;
+ try {
+ permInfo = mContext.getPackageManager().getPermissionInfo(requestedPerm, 0);
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "Unknown permission: " + requestedPerm);
+ continue;
+ }
+
+ String permName = permInfo.name;
+ String groupName = permInfo.group != null ? permInfo.group : permName;
+
+ PermissionGroup group = mGroups.get(groupName);
+ if (group == null) {
+ PermissionGroupInfo groupInfo = null;
+ if (permInfo.group != null) {
+ try {
+ groupInfo = mContext.getPackageManager().getPermissionGroupInfo(
+ permInfo.group, 0);
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "Unknown group: " + permInfo.group);
+ }
+ }
+
+ CharSequence groupLabel = (groupInfo != null)
+ ? groupInfo.loadLabel(mContext.getPackageManager())
+ : permInfo.loadLabel(mContext.getPackageManager());
+
+ if (groupLabel == null) {
+ Log.w(LOG_TAG, "Neither permission nor group have name."
+ + " Ignoring permission: " + permInfo.name);
+ continue;
+ }
+
+ final int iconResId = (groupInfo != null) ? groupInfo.icon : permInfo.icon;
+
+ group = new PermissionGroup(mContext, mPackageInfo.packageName,
+ groupName, groupLabel, iconResId);
+ mGroups.put(groupName, group);
+ }
+
+ final boolean runtime = appSupportsRuntimePermissions
+ && permInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS;
+ final boolean granted = (mPackageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+
+ Permission permission = new Permission(permName, runtime, granted);
+ group.addPermission(permission);
+ }
+
+ if (ArrayUtils.isEmpty(mFilterPermissions)) {
+ return;
+ }
+
+ final int groupCount = mGroups.size();
+ for (int i = groupCount - 1; i >= 0; i--) {
+ PermissionGroup group = mGroups.valueAt(i);
+ boolean groupHasPermission = false;
+ for (String filterPerm : mFilterPermissions) {
+ if (group.mPermissions.containsKey(filterPerm)) {
+ groupHasPermission = true;
+ break;
+ }
+ }
+ if (!groupHasPermission) {
+ mGroups.removeAt(i);
+ }
+ }
+ }
+
+ public static final class PermissionGroup {
+ private final Context mContext;
+ private final String mPackageName;
+
+ private final String mName;
+ private final CharSequence mLabel;
+ private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>();
+ private final int mIconResId;
+
+ private boolean mHasRuntimePermissions;
+
+ public String getName() {
+ return mName;
+ }
+
+ public int getIconResId() {
+ return mIconResId;
+ }
+
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ public PermissionGroup(Context context, String packageName,
+ String name, CharSequence label, int iconResId) {
+ mPackageName = packageName;
+ mContext = context;
+ mName = name;
+ mLabel = label;
+ mIconResId = iconResId;
+ }
+
+ public boolean hasRuntimePermissions() {
+ return mHasRuntimePermissions;
+ }
+
+ public boolean areRuntimePermissionsGranted() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.mRuntime && !permission.mGranted) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean grantRuntimePermissions() {
+ for (Permission permission : mPermissions.values()) {
+ if (permission.mRuntime && !permission.mGranted) {
+ mContext.getPackageManager().grantPermission(mPackageName,
+ permission.mName, new UserHandle(mContext.getUserId()));
+ permission.mGranted = true;
+ }
+ }
+ return true;
+ }
+
+ public boolean revokeRuntimePermissions() {
+ for (Permission permission : mPermissions.values()) {
+ if (permission.mRuntime && permission.mGranted) {
+ mContext.getPackageManager().revokePermission(mPackageName,
+ permission.mName, new UserHandle(mContext.getUserId()));
+ permission.mGranted = false;
+ }
+ }
+ return true;
+ }
+
+ public List<Permission> getPermissions() {
+ return new ArrayList<>(mPermissions.values());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ PermissionGroup other = (PermissionGroup) obj;
+
+ if (mName == null) {
+ if (other.mName != null) {
+ return false;
+ }
+ } else if (!mName.equals(other.mName)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return mName != null ? mName.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getClass().getSimpleName());
+ builder.append("{name=").append(mName);
+ if (!mPermissions.isEmpty()) {
+ builder.append(", <has permissions>}");
+ } else {
+ builder.append('}');
+ }
+ return builder.toString();
+ }
+
+ void addPermission(Permission permission) {
+ mPermissions.put(permission.mName, permission);
+ if (permission.mRuntime) {
+ mHasRuntimePermissions = true;
+ }
+ }
+ }
+
+ public static final class Permission {
+ private final String mName;
+ private final boolean mRuntime;
+ private boolean mGranted;
+
+ public Permission(String name, boolean runtime, boolean granted) {
+ mName = name;
+ mRuntime = runtime;
+ mGranted = granted;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public boolean isGranted() {
+ return mGranted;
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/GrantPermissionFragment.java b/src/com/android/packageinstaller/permission/GrantPermissionFragment.java
new file mode 100644
index 00000000..65b60687
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/GrantPermissionFragment.java
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+import android.app.DialogFragment;
+import android.os.Bundle;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.packageinstaller.R;
+
+public final class GrantPermissionFragment extends DialogFragment {
+ public static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
+ public static final String ARG_GROUP_COUNT = "ARG_GROUP_COUNT";
+ public static final String ARG_GROUP_INDEX = "ARG_GROUP_INDEX";
+ public static final String ARG_GROUP_ICON_RES_ID = "ARG_GROUP_ICON";
+ public static final String ARG_GROUP_MESSAGE = "ARG_GROUP_MESSAGE";
+
+ public interface OnRequestGrantPermissionGroupResult {
+ public void onRequestGrantPermissionGroupResult(String name, boolean granted);
+ }
+
+ public static GrantPermissionFragment newInstance(String groupName,
+ int groupCount, int groupIndex, int iconResId, CharSequence message) {
+ GrantPermissionFragment instance = new GrantPermissionFragment();
+ instance.setStyle(STYLE_NORMAL,
+ android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
+
+ Bundle arguments = new Bundle();
+ arguments.putString(ARG_GROUP_NAME, groupName);
+ arguments.putInt(ARG_GROUP_COUNT, groupCount);
+ arguments.putInt(ARG_GROUP_INDEX, groupIndex);
+ arguments.putInt(ARG_GROUP_ICON_RES_ID, iconResId);
+ arguments.putCharSequence(ARG_GROUP_MESSAGE, message);
+ instance.setArguments(arguments);
+
+ return instance;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View content = inflater.inflate(R.layout.grant_permissions, container, false);
+
+ final String groupName = getArguments().getString(ARG_GROUP_NAME);
+ final String message = getArguments().getString(ARG_GROUP_MESSAGE);
+ final int iconResId = getArguments().getInt(ARG_GROUP_ICON_RES_ID);
+ final int groupCount = getArguments().getInt(ARG_GROUP_COUNT);
+ final int groupIndex = getArguments().getInt(ARG_GROUP_INDEX);
+
+ final ImageView iconView = (ImageView) content.findViewById(R.id.permission_icon);
+ final View allowButton = content.findViewById(R.id.permission_allow_button);
+ final View denyButton = content.findViewById(R.id.permission_deny_button);
+ final View doNotAskCheckbox = content.findViewById(R.id.do_not_ask_checkbox);
+ final TextView currentGroupView = (TextView) content.findViewById(R.id.current_page_text);
+ final TextView messageView = (TextView) content.findViewById(R.id.permission_message);
+
+ OnClickListener clickListener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (view == allowButton) {
+ ((OnRequestGrantPermissionGroupResult) getActivity())
+ .onRequestGrantPermissionGroupResult(groupName, true);
+ } else if (view == denyButton) {
+ ((OnRequestGrantPermissionGroupResult) getActivity())
+ .onRequestGrantPermissionGroupResult(groupName, false);
+ } else if (view == doNotAskCheckbox) {
+ //TODO: Implement me.
+ }
+ }
+ };
+
+ iconView.setImageResource(iconResId);
+
+ messageView.setText(message);
+
+ allowButton.setOnClickListener(clickListener);
+ denyButton.setOnClickListener(clickListener);
+ doNotAskCheckbox.setOnClickListener(clickListener);
+
+ if (groupCount > 1) {
+ currentGroupView.setVisibility(View.VISIBLE);
+ currentGroupView.setText(getString(R.string.current_permission_template,
+ groupIndex + 1, groupCount));
+ } else {
+ currentGroupView.setVisibility(View.INVISIBLE);
+ }
+
+ return content;
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/GrantPermissionsActivity.java
new file mode 100644
index 00000000..4c3eb247
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/GrantPermissionsActivity.java
@@ -0,0 +1,246 @@
+/*
+ * 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;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionInfo;
+import android.hardware.camera2.utils.ArrayUtils;
+import android.os.Bundle;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.AppPermissions.Permission;
+import com.android.packageinstaller.permission.AppPermissions.PermissionGroup;
+
+public class GrantPermissionsActivity extends Activity implements
+ GrantPermissionFragment.OnRequestGrantPermissionGroupResult {
+ private static final String LOG_TAG = "GrantPermissionsActivity";
+
+ private static final String TAG_GRANT_PERMISSION_GROUP_FRAGMENT =
+ "TAG_GRANT_PERMISSION_GROUP_FRAGMENT";
+
+ private static final int PERMISSION_GRANTED = 1;
+ private static final int PERMISSION_DENIED = 2;
+ private static final int PERMISSION_DENIED_RUNTIME = 3;
+
+ private String[] mRequestedPermissions;
+ private int[] mGrantResults;
+ private final SparseArray<String> mRequestedRuntimePermissions = new SparseArray<>();
+
+ private ArrayMap<String, GroupState> mRequestGrantPermissionGroups = new ArrayMap<>();
+
+ private AppPermissions mAppPermissions;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mRequestedPermissions = getIntent().getStringArrayExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
+ if (mRequestedPermissions == null) {
+ mRequestedPermissions = new String[0];
+ }
+
+ mGrantResults = new int[mRequestedPermissions.length];
+
+ final int requestedPermCount = mRequestedPermissions.length;
+ if (requestedPermCount == 0) {
+ setResultAndFinish();
+ return;
+ }
+
+ PackageInfo callingPackageInfo = getCallingPackageInfo();
+ if (callingPackageInfo == null) {
+ setResultAndFinish();
+ return;
+ }
+
+ updateDefaultResults(callingPackageInfo);
+
+ mAppPermissions = new AppPermissions(this, callingPackageInfo, mRequestedPermissions);
+
+ for (PermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ if (group.hasRuntimePermissions() && !group.areRuntimePermissionsGranted()) {
+ mRequestGrantPermissionGroups.put(group.getName(), new GroupState(group));
+ }
+ }
+
+ if (!showNextPermissionGroupFragment()) {
+ setResultAndFinish();
+ }
+ }
+
+ private boolean showNextPermissionGroupFragment() {
+ final int groupCount = mRequestGrantPermissionGroups.size();
+
+ for (int i = 0; i < groupCount; i++) {
+ GroupState groupState = mRequestGrantPermissionGroups.valueAt(i);
+ if (groupState.mGroup.hasRuntimePermissions()
+ && !groupState.mGroup.areRuntimePermissionsGranted()
+ && groupState.mState == GroupState.STATE_UNKNOWN) {
+ // Make sure adding the fragment we will remove is not in flight.
+ getFragmentManager().executePendingTransactions();
+
+ // Remove old grant fragment if such exists.
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ Fragment oldFragment = getFragmentManager().findFragmentByTag(
+ TAG_GRANT_PERMISSION_GROUP_FRAGMENT);
+ if (oldFragment != null) {
+ transaction.remove(oldFragment);
+ }
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
+ transaction.commit();
+
+ CharSequence message = getString(R.string.permission_warning_template,
+ mAppPermissions.getAppLabel(), groupState.mGroup.getLabel());
+
+ // Add the new grant fragment.
+ // TODO: Use a real message for the action and a real icon. We need group action APIs
+ DialogFragment newFragment = GrantPermissionFragment
+ .newInstance(groupState.mGroup.getName(), groupCount, i,
+ android.R.drawable.ic_dialog_info, message);
+
+ newFragment.show(getFragmentManager(), TAG_GRANT_PERMISSION_GROUP_FRAGMENT);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onRequestGrantPermissionGroupResult(String name, boolean granted) {
+ GroupState groupState = mRequestGrantPermissionGroups.get(name);
+ if (groupState.mGroup != null) {
+ if (granted) {
+ groupState.mGroup.grantRuntimePermissions();
+ groupState.mState = GroupState.STATE_ALLOWED;
+ updateGrantResults(groupState.mGroup);
+ } else {
+ groupState.mState = GroupState.STATE_DENIED;
+ }
+ }
+ if (!showNextPermissionGroupFragment()) {
+ setResultAndFinish();
+ }
+ }
+
+ private void updateGrantResults(PermissionGroup group) {
+ for (Permission permission : group.getPermissions()) {
+ if (permission.isGranted()) {
+ final int index = ArrayUtils.getArrayIndex(
+ mRequestedPermissions, permission.getName());
+ if (index >= 0) {
+ mGrantResults[index] = PackageManager.PERMISSION_GRANTED;
+ }
+ }
+ }
+ }
+
+ private int computePermissionGrantState(PackageInfo callingPackageInfo, String permission) {
+ boolean permissionRequested = false;
+
+ for (int i = 0; i < callingPackageInfo.requestedPermissions.length; i++) {
+ if (permission.equals(callingPackageInfo.requestedPermissions[i])) {
+ permissionRequested = true;
+ if ((callingPackageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
+ return PERMISSION_GRANTED;
+ }
+ break;
+ }
+ }
+
+ if (!permissionRequested) {
+ return PERMISSION_DENIED;
+ }
+
+ try {
+ PermissionInfo pInfo = getPackageManager().getPermissionInfo(permission, 0);
+ if ((pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ != PermissionInfo.PROTECTION_DANGEROUS) {
+ return PERMISSION_DENIED;
+ }
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+
+ return PERMISSION_DENIED_RUNTIME;
+ }
+
+ private PackageInfo getCallingPackageInfo() {
+ try {
+ return getPackageManager().getPackageInfo(getCallingPackage(),
+ PackageManager.GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
+ Log.i(LOG_TAG, "No package:" + getCallingPackage(), e);
+ return null;
+ }
+ }
+
+ private void updateDefaultResults(PackageInfo callingPackageInfo) {
+ final int requestedPermCount = mRequestedPermissions.length;
+ for (int i = 0; i < requestedPermCount; i++) {
+ String permission = mRequestedPermissions[i];
+ final int state = computePermissionGrantState(callingPackageInfo, permission);
+ switch (state) {
+ case PERMISSION_GRANTED: {
+ mGrantResults[i] = PackageManager.PERMISSION_GRANTED;
+ } break;
+
+ case PERMISSION_DENIED: {
+ mGrantResults[i] = PackageManager.PERMISSION_DENIED;
+ } break;
+
+ case PERMISSION_DENIED_RUNTIME: {
+ mGrantResults[i] = PackageManager.PERMISSION_DENIED;
+ mRequestedRuntimePermissions.put(i, permission);
+ } break;
+ }
+ }
+ }
+
+ private void setResultAndFinish() {
+ Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS);
+ result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, mRequestedPermissions);
+ result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS, mGrantResults);
+ setResult(RESULT_OK, result);
+ finish();
+ }
+
+ private static final class GroupState {
+ public static final int STATE_UNKNOWN = 0;
+ public static final int STATE_ALLOWED = 1;
+ public static final int STATE_DENIED = 2;
+
+ public final PermissionGroup mGroup;
+ public int mState = STATE_UNKNOWN;
+
+ public GroupState(PermissionGroup group) {
+ mGroup = group;
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ManagePermissionsActivity.java b/src/com/android/packageinstaller/permission/ManagePermissionsActivity.java
new file mode 100644
index 00000000..598f5e02
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ManagePermissionsActivity.java
@@ -0,0 +1,41 @@
+/*
+* 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;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public final class ManagePermissionsActivity extends Activity {
+ private static final String LOG_TAG = "ManagePermissionsActivity";
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (packageName == null) {
+ Log.i(LOG_TAG, "Missing mandatory argument ARG_PACKAGE_NAME");
+ finish();
+ return;
+ }
+
+ ManagePermissionsFragment fragment = ManagePermissionsFragment.newInstance(packageName);
+ getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit();
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ManagePermissionsFragment.java b/src/com/android/packageinstaller/permission/ManagePermissionsFragment.java
new file mode 100644
index 00000000..75e30aef
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ManagePermissionsFragment.java
@@ -0,0 +1,128 @@
+/*
+* 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;
+
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.util.Log;
+
+public final class ManagePermissionsFragment extends PreferenceFragment {
+ private static final String LOG_TAG = "ManagePermissionsFragment";
+
+ private AppPermissions mAppPermissions;
+
+ public static ManagePermissionsFragment newInstance(String packageName) {
+ ManagePermissionsFragment instance = new ManagePermissionsFragment();
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ instance.setArguments(arguments);
+ return instance;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindUi();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateUi();
+ }
+
+ private void bindUi() {
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+
+ final PackageInfo packageInfo = getPackageInfo(packageName);
+ if (packageInfo == null) {
+ getActivity().finish();
+ return;
+ }
+
+ PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ mAppPermissions = new AppPermissions(getActivity(),
+ packageInfo, null);
+
+ Preference.OnPreferenceChangeListener changeListener =
+ new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String groupName = preference.getKey();
+ AppPermissions.PermissionGroup group = mAppPermissions
+ .getPermissionGroup(groupName);
+
+ if (group == null) {
+ return false;
+ }
+
+ if (newValue == Boolean.TRUE) {
+ group.grantRuntimePermissions();
+ } else {
+ group.revokeRuntimePermissions();
+ }
+
+ return true;
+ }
+ };
+
+ for (AppPermissions.PermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ if (group.hasRuntimePermissions()) {
+ SwitchPreference preference = new SwitchPreference(getActivity());
+ preference.setOnPreferenceChangeListener(changeListener);
+ preference.setKey(group.getName());
+ preference.setIcon(group.getIconResId());
+ preference.setTitle(group.getLabel());
+ preference.setPersistent(false);
+ screen.addPreference(preference);
+ }
+ }
+
+ setPreferenceScreen(screen);
+ }
+
+ private void updateUi() {
+ mAppPermissions.refresh();
+
+ final int preferenceCount = getPreferenceScreen().getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ SwitchPreference preference = (SwitchPreference)
+ getPreferenceScreen().getPreference(i);
+ AppPermissions.PermissionGroup group = mAppPermissions
+ .getPermissionGroup(preference.getKey());
+ if (group != null) {
+ preference.setChecked(group.areRuntimePermissionsGranted());
+ }
+ }
+ }
+
+ private PackageInfo getPackageInfo(String packageName) {
+ try {
+ return getActivity().getPackageManager().getPackageInfo(
+ packageName, PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(LOG_TAG, "No package:" + getActivity().getCallingPackage(), e);
+ return null;
+ }
+ }
+} \ No newline at end of file