summaryrefslogtreecommitdiffstats
path: root/src/com/android/packageinstaller/permission/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/packageinstaller/permission/ui')
-rw-r--r--src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java198
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionFragment.java129
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java258
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java58
-rw-r--r--src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java164
-rw-r--r--src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java82
6 files changed, 889 insertions, 0 deletions
diff --git a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
new file mode 100644
index 00000000..a74f08c8
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
@@ -0,0 +1,198 @@
+/*
+* 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.ActionBar;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.utils.Utils;
+import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.model.PermissionGroup;
+
+public final class AppPermissionsFragment extends SettingsWithHeader
+ implements OnPreferenceChangeListener {
+ private static final String LOG_TAG = "ManagePermsFragment";
+
+ private AppPermissions mAppPermissions;
+
+ public static AppPermissionsFragment newInstance(String packageName) {
+ AppPermissionsFragment instance = new AppPermissionsFragment();
+ 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);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateUi();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getActivity().finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container,
+ false);
+ ViewGroup prefsContainer = (ViewGroup) rootView.findViewById(R.id.prefs_container);
+ if (prefsContainer == null) {
+ prefsContainer = rootView;
+ }
+ prefsContainer.addView(super.onCreateView(inflater, prefsContainer, savedInstanceState));
+ View emptyView = rootView.findViewById(R.id.no_permissions);
+ ((ListView) rootView.findViewById(android.R.id.list)).setEmptyView(emptyView);
+ return rootView;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindUi();
+ }
+
+ private void bindUi() {
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+
+ final Activity activity = getActivity();
+ PackageInfo packageInfo = getPackageInfo(packageName);
+ if (packageInfo == null) {
+ Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG)
+ .show();
+ activity.finish();
+ return;
+ }
+ final PackageManager pm = activity.getPackageManager();
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+ final Drawable icon = appInfo.loadIcon(pm);
+ final CharSequence label = appInfo.loadLabel(pm);
+ setHeader(icon, label, null);
+
+ final ViewGroup rootView = (ViewGroup) getView();
+ final ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ iconView.setImageDrawable(icon);
+ }
+ final TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(R.string.app_permissions);
+ }
+ final TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(label);
+ }
+
+ PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(activity);
+ mAppPermissions = new AppPermissions(activity, packageInfo, null);
+
+ for (PermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ SwitchPreference preference = new SwitchPreference(activity);
+ preference.setOnPreferenceChangeListener(this);
+ preference.setKey(group.getName());
+ preference.setIcon(Utils.loadDrawable(pm, group.getIconPkg(),
+ group.getIconResId()));
+ preference.setTitle(group.getLabel());
+ preference.setPersistent(false);
+ screen.addPreference(preference);
+ }
+
+ setPreferenceScreen(screen);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String groupName = preference.getKey();
+ PermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
+
+ if (group == null) {
+ return false;
+ }
+
+ if (newValue == Boolean.TRUE) {
+ group.grantRuntimePermissions();
+ } else {
+ group.revokeRuntimePermissions();
+ }
+
+ return true;
+ }
+
+ private void updateUi() {
+ mAppPermissions.refresh();
+
+ final int preferenceCount = getPreferenceScreen().getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ SwitchPreference preference = (SwitchPreference)
+ getPreferenceScreen().getPreference(i);
+ 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
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionFragment.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionFragment.java
new file mode 100644
index 00000000..0458f9b9
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionFragment.java
@@ -0,0 +1,129 @@
+/*
+ * 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.DialogFragment;
+import android.content.DialogInterface;
+import android.graphics.drawable.Drawable;
+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;
+import com.android.packageinstaller.permission.utils.Utils;
+
+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_ICON_PKG = "ARG_GROUP_ICON_PKG";
+ 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, String iconPkg, 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.putString(ARG_GROUP_ICON_PKG, iconPkg);
+ arguments.putCharSequence(ARG_GROUP_MESSAGE, message);
+ instance.setArguments(arguments);
+
+ return instance;
+ }
+
+ private String mGroupName;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View content = inflater.inflate(R.layout.grant_permissions, container, false);
+
+ mGroupName = getArguments().getString(ARG_GROUP_NAME);
+ final CharSequence message = getArguments().getCharSequence(ARG_GROUP_MESSAGE);
+ final String iconPkg = getArguments().getString(ARG_GROUP_ICON_PKG);
+ 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(mGroupName, true);
+ } else if (view == denyButton) {
+ ((OnRequestGrantPermissionGroupResult) getActivity())
+ .onRequestGrantPermissionGroupResult(mGroupName, false);
+ } else if (view == doNotAskCheckbox) {
+ //TODO: Implement me.
+ }
+ }
+ };
+
+ Drawable icon = Utils.loadDrawable(getActivity().getPackageManager(), iconPkg,
+ iconResId);
+ iconView.setImageDrawable(icon);
+
+ 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;
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ Activity activity = getActivity();
+ if (activity != null) {
+ ((OnRequestGrantPermissionGroupResult) getActivity())
+ .onRequestGrantPermissionGroupResult(mGroupName, false);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
new file mode 100644
index 00000000..02951e9f
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -0,0 +1,258 @@
+/*
+ * 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.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.text.SpannableString;
+import android.text.style.ForegroundColorSpan;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.model.Permission;
+import com.android.packageinstaller.permission.model.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.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.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 appLabel = mAppPermissions.getAppLabel();
+ SpannableString message = new SpannableString(getString(
+ R.string.permission_warning_template, appLabel,
+ groupState.mGroup.getLabel()));
+ // Bold/color the app name.
+ int appLabelStart = message.toString().indexOf(appLabel.toString(), 0);
+ int appLabelLength = appLabel.length();
+ int color = getResources().getColor(R.color.grant_permissions_app_color, null);
+ message.setSpan(new ForegroundColorSpan(color), appLabelStart,
+ appLabelStart + appLabelLength, 0);
+
+ // Add the new grant fragment.
+ // TODO: Use a real message for the action. We need group action APIs
+ String pkg = groupState.mGroup.getIconPkg();
+ int icon = groupState.mGroup.getIconResId();
+ DialogFragment newFragment = GrantPermissionFragment
+ .newInstance(groupState.mGroup.getName(), groupCount, i,
+ pkg, icon, 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/ui/ManagePermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
new file mode 100644
index 00000000..ef117a9c
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
@@ -0,0 +1,58 @@
+/*
+* 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.Fragment;
+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);
+
+ Fragment fragment = null;
+ String action = getIntent().getAction();
+ if (Intent.ACTION_MANAGE_APP_PERMISSIONS.equals(action)) {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (packageName == null) {
+ Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME");
+ finish();
+ return;
+ }
+ fragment = AppPermissionsFragment.newInstance(packageName);
+ } else if (Intent.ACTION_MANAGE_PERMISSION_APPS.equals(action)) {
+ String permissionName = getIntent().getStringExtra(Intent.EXTRA_PERMISSION_NAME);
+ if (permissionName == null) {
+ Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PERMISSION_NAME");
+ finish();
+ return;
+ }
+ fragment = PermissionAppsFragment.newInstance(permissionName);
+ } else {
+ Log.w(LOG_TAG, "Unrecognized action " + action);
+ finish();
+ return;
+ }
+
+ getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit();
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
new file mode 100644
index 00000000..f5d7d711
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
@@ -0,0 +1,164 @@
+/*
+ * 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.ActionBar;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.PermissionApps;
+import com.android.packageinstaller.permission.model.PermissionApps.Callback;
+import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+
+public final class PermissionAppsFragment extends SettingsWithHeader implements Callback,
+ OnPreferenceChangeListener {
+
+ public static PermissionAppsFragment newInstance(String permissionName) {
+ PermissionAppsFragment instance = new PermissionAppsFragment();
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName);
+ instance.setArguments(arguments);
+ return instance;
+ }
+
+ private PermissionApps mPermissionApps;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPermissionApps.refresh();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getActivity().finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container,
+ false);
+ ViewGroup prefsContainer = (ViewGroup) rootView.findViewById(R.id.prefs_container);
+ if (prefsContainer == null) {
+ prefsContainer = rootView;
+ }
+ prefsContainer.addView(super.onCreateView(inflater, prefsContainer, savedInstanceState));
+ View emptyView = rootView.findViewById(R.id.no_permissions);
+ if (emptyView != null) {
+ emptyView.setVisibility(View.GONE);
+ }
+ return rootView;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindUi();
+ }
+
+ private void bindUi() {
+ String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
+ mPermissionApps = new PermissionApps(getActivity(), groupName, this);
+ final Drawable icon = mPermissionApps.getIcon();
+ final CharSequence label = mPermissionApps.getLabel();
+ setHeader(icon, label, null);
+
+ final ViewGroup rootView = (ViewGroup) getView();
+ final ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ iconView.setImageDrawable(icon);
+ }
+ final TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(label);
+ }
+ final TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(R.string.app_permissions);
+ }
+ }
+
+ @Override
+ public void onPermissionsLoaded() {
+ Context context = getActivity();
+ PreferenceScreen preferences = getPreferenceScreen();
+ if (preferences == null) {
+ preferences = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(preferences);
+ }
+ preferences.removeAll();
+ for (PermissionApp app : mPermissionApps.getApps()) {
+ SwitchPreference pref = (SwitchPreference) findPreference(app.getKey());
+ if (pref == null) {
+ pref = new SwitchPreference(context);
+ pref.setOnPreferenceChangeListener(this);
+ pref.setKey(app.getKey());
+ pref.setIcon(app.getIcon());
+ pref.setTitle(app.getLabel());
+ pref.setPersistent(false);
+ preferences.addPreference(pref);
+ }
+ pref.setChecked(app.areRuntimePermissionsGranted());
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String pkg = preference.getKey();
+ PermissionApp app = mPermissionApps.getApp(pkg);
+
+ if (app == null) {
+ return false;
+ }
+ if (newValue == Boolean.TRUE) {
+ app.grantRuntimePermissions();
+ } else {
+ app.revokeRuntimePermissions();
+ }
+ return true;
+ }
+
+}
diff --git a/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java b/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java
new file mode 100644
index 00000000..e1e3abe2
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java
@@ -0,0 +1,82 @@
+/*
+ * 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.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+
+public abstract class SettingsWithHeader extends PreferenceFragment implements OnClickListener {
+
+ private View mHeader;
+ private Intent mInfoIntent;
+ private Drawable mIcon;
+ private CharSequence mLabel;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ LinearLayout contentParent =
+ (LinearLayout) super.onCreateView(inflater, container, savedInstanceState);
+ mHeader = inflater.inflate(R.layout.header, contentParent, false);
+ contentParent.addView(mHeader, 0);
+ updateHeader();
+
+ return contentParent;
+ }
+
+ public void setHeader(Drawable icon, CharSequence label, Intent infoIntent) {
+ mIcon = icon;
+ mLabel = label;
+ mInfoIntent = infoIntent;
+ updateHeader();
+ }
+
+ private void updateHeader() {
+ if (mHeader != null) {
+ final ImageView appIcon = (ImageView) mHeader.findViewById(R.id.icon);
+ appIcon.setImageDrawable(mIcon);
+
+ final TextView appName = (TextView) mHeader.findViewById(R.id.name);
+ appName.setText(mLabel);
+
+ final View info = mHeader.findViewById(R.id.info);
+ if (mInfoIntent == null) {
+ info.setVisibility(View.GONE);
+ } else {
+ info.setClickable(true);
+ info.setOnClickListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ getActivity().startActivity(mInfoIntent);
+ }
+
+}