summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2015-11-20 14:00:11 -0800
committerSvetoslav <svetoslavganov@google.com>2015-11-20 14:02:19 -0800
commitef861375eebd9ac6cce7c0bb163380ab1c951063 (patch)
tree870ae89605e49658de3e5abca2797b68c5efbb26 /src
parent9c78316fe6baa4f7fd7d5108349ecf8a2532b047 (diff)
downloadandroid_packages_apps_PackageInstaller-ef861375eebd9ac6cce7c0bb163380ab1c951063.tar.gz
android_packages_apps_PackageInstaller-ef861375eebd9ac6cce7c0bb163380ab1c951063.tar.bz2
android_packages_apps_PackageInstaller-ef861375eebd9ac6cce7c0bb163380ab1c951063.zip
resolve merge conflicts of c10abb25f3 to cw-e-dev.
Change-Id: I3fe38a9ac62466b38efec834dceb712d2782c518
Diffstat (limited to 'src')
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionApps.java3
-rw-r--r--src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java117
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java12
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java2
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java24
-rw-r--r--src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java1
-rw-r--r--src/com/android/packageinstaller/permission/ui/PreferenceImageView.java69
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java214
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java404
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java (renamed from src/com/android/packageinstaller/permission/ui/GrantPermissionsDefaultViewHandler.java)16
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java268
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java427
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java121
-rw-r--r--src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java84
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/AllAppPermissionsFragment.java)2
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java)3
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java (renamed from src/com/android/packageinstaller/permission/ui/GrantPermissionsTvViewHandler.java)9
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java)4
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java (renamed from src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java)3
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java203
-rw-r--r--src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java85
-rw-r--r--src/com/android/packageinstaller/permission/utils/LocationUtils.java17
22 files changed, 2044 insertions, 44 deletions
diff --git a/src/com/android/packageinstaller/permission/model/PermissionApps.java b/src/com/android/packageinstaller/permission/model/PermissionApps.java
index 9365bf13..e5d96d55 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionApps.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionApps.java
@@ -31,6 +31,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
+import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.utils.Utils;
import java.util.ArrayList;
@@ -275,7 +276,7 @@ public class PermissionApps {
if (info.icon != 0) {
mIcon = info.loadUnbadgedIcon(mPm);
} else {
- mIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_perm_device_info);
+ mIcon = mContext.getDrawable(R.drawable.ic_perm_device_info);
}
mIcon = Utils.applyTint(mContext, mIcon, android.R.attr.colorControlNormal);
}
diff --git a/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java b/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java
new file mode 100644
index 00000000..59e54707
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/ButtonBarLayout.java
@@ -0,0 +1,117 @@
+/*
+ * 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.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+import com.android.packageinstaller.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+ /** Whether the current configuration allows stacking. */
+ private boolean mAllowStacking;
+
+ private int mLastWidthSize = -1;
+
+ public ButtonBarLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAllowStacking = true;
+ }
+
+ public void setAllowStacking(boolean allowStacking) {
+ if (mAllowStacking != allowStacking) {
+ mAllowStacking = allowStacking;
+ if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) {
+ setStacked(false);
+ }
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+
+ if (mAllowStacking) {
+ if (widthSize > mLastWidthSize && isStacked()) {
+ // We're being measured wider this time, try un-stacking.
+ setStacked(false);
+ }
+
+ mLastWidthSize = widthSize;
+ }
+
+ boolean needsRemeasure = false;
+
+ // If we're not stacked, make sure the measure spec is AT_MOST rather
+ // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
+ // know to stack the buttons.
+ final int initialWidthMeasureSpec;
+ if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+ initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+
+ // We'll need to remeasure again to fill excess space.
+ needsRemeasure = true;
+ } else {
+ initialWidthMeasureSpec = widthMeasureSpec;
+ }
+
+ super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+
+ if (mAllowStacking && !isStacked()) {
+ final int measuredWidth = getMeasuredWidthAndState();
+ final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+ if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+ setStacked(true);
+
+ // Measure again in the new orientation.
+ needsRemeasure = true;
+ }
+ }
+
+ if (needsRemeasure) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ private void setStacked(boolean stacked) {
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+
+ final View spacer = findViewById(R.id.spacer);
+ if (spacer != null) {
+ spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+ }
+
+ // Reverse the child order. This is specific to the Material button
+ // bar's layout XML and will probably not generalize.
+ final int childCount = getChildCount();
+ for (int i = childCount - 2; i >= 0; i--) {
+ bringChildToFront(getChildAt(i));
+ }
+ }
+
+ private boolean isStacked() {
+ return getOrientation() == LinearLayout.VERTICAL;
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index ffa8bf35..102fd6ef 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -26,11 +26,12 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.content.res.Resources;
+import android.graphics.Typeface;
import android.graphics.drawable.Icon;
import android.hardware.camera2.utils.ArrayUtils;
import android.os.Bundle;
import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -73,11 +74,13 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
setTitle(R.string.permission_request_title);
if (DeviceUtils.isTelevision(this)) {
- mViewHandler = new GrantPermissionsTvViewHandler(this).setResultListener(this);
+ mViewHandler = new com.android.packageinstaller.permission.ui.television
+ .GrantPermissionsViewHandlerImpl(this).setResultListener(this);
} else if (DeviceUtils.isWear(this)) {
mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this);
} else {
- mViewHandler = new GrantPermissionsDefaultViewHandler(this).setResultListener(this);
+ mViewHandler = new com.android.packageinstaller.permission.ui.handheld
+ .GrantPermissionsViewHandlerImpl(this).setResultListener(this);
}
mRequestedPermissions = getIntent().getStringArrayExtra(
@@ -209,8 +212,7 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
// Color the app name.
int appLabelStart = message.toString().indexOf(appLabel.toString(), 0);
int appLabelLength = appLabel.length();
- int color = getColor(R.color.grant_permissions_app_color);
- message.setSpan(new ForegroundColorSpan(color), appLabelStart,
+ message.setSpan(new StyleSpan(Typeface.BOLD), appLabelStart,
appLabelStart + appLabelLength, 0);
// Set the new grant view
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java
index 4032abb2..5e2259af 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsViewHandler.java
@@ -25,7 +25,7 @@ import android.view.WindowManager;
* Class for managing the presentation and user interaction of the "grant
* permissions" user interface.
*/
-interface GrantPermissionsViewHandler {
+public interface GrantPermissionsViewHandler {
/**
* Listener interface for getting notified when the user responds to a
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
index f7fcec5e..419dbf42 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
@@ -20,6 +20,7 @@ import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import com.android.packageinstaller.permission.utils.Utils;
import com.android.packageinstaller.permission.ui.wear.AppPermissionsFragmentWear;
import com.android.packageinstaller.DeviceUtils;
@@ -40,7 +41,13 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
switch (action) {
case Intent.ACTION_MANAGE_PERMISSIONS: {
- fragment = ManagePermissionsFragment.newInstance();
+ if (Utils.isTelevision(this)) {
+ fragment = com.android.packageinstaller.permission.ui.television
+ .ManagePermissionsFragment.newInstance();
+ } else {
+ fragment = com.android.packageinstaller.permission.ui.handheld
+ .ManagePermissionsFragment.newInstance();
+ }
} break;
case Intent.ACTION_MANAGE_APP_PERMISSIONS: {
@@ -50,11 +57,14 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
finish();
return;
}
-
if (DeviceUtils.isWear(this)) {
fragment = AppPermissionsFragmentWear.newInstance(packageName);
+ } else if (Utils.isTelevision(this)) {
+ fragment = com.android.packageinstaller.permission.ui.television
+ .AppPermissionsFragment.newInstance(packageName);
} else {
- fragment = AppPermissionsFragment.newInstance(packageName);
+ fragment = com.android.packageinstaller.permission.ui.handheld
+ .AppPermissionsFragment.newInstance(packageName);
}
} break;
@@ -65,7 +75,13 @@ public final class ManagePermissionsActivity extends OverlayTouchActivity {
finish();
return;
}
- fragment = PermissionAppsFragment.newInstance(permissionName);
+ if (Utils.isTelevision(this)) {
+ fragment = com.android.packageinstaller.permission.ui.television
+ .PermissionAppsFragment.newInstance(permissionName);
+ } else {
+ fragment = com.android.packageinstaller.permission.ui.handheld
+ .PermissionAppsFragment.newInstance(permissionName);
+ }
} break;
default: {
diff --git a/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java b/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java
index a7c1e2a1..61734b47 100644
--- a/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java
+++ b/src/com/android/packageinstaller/permission/ui/OverlayWarningDialog.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.packageinstaller.permission.ui;
import android.app.Activity;
diff --git a/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java b/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java
new file mode 100644
index 00000000..c3f51674
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/PreferenceImageView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 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.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * Extension of ImageView that correctly applies maxWidth and maxHeight.
+ */
+public class PreferenceImageView extends ImageView {
+
+ public PreferenceImageView(Context context) {
+ this(context, null);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int maxWidth = getMaxWidth();
+ if (maxWidth != Integer.MAX_VALUE
+ && (maxWidth < widthSize || widthMode == MeasureSpec.UNSPECIFIED)) {
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
+ }
+ }
+
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int maxHeight = getMaxHeight();
+ if (maxHeight != Integer.MAX_VALUE
+ && (maxHeight < heightSize || heightMode == MeasureSpec.UNSPECIFIED)) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
+ }
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java
new file mode 100644
index 00000000..b3b0895c
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/AllAppPermissionsFragment.java
@@ -0,0 +1,214 @@
+/*
+* 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.handheld;
+
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.MenuItem;
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+public final class AllAppPermissionsFragment extends SettingsWithHeader {
+
+ private static final String LOG_TAG = "AllAppPermissionsFragment";
+
+ private static final String KEY_OTHER = "other_perms";
+
+ public static AllAppPermissionsFragment newInstance(String packageName) {
+ AllAppPermissionsFragment instance = new AllAppPermissionsFragment();
+ 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.setTitle(R.string.all_permissions);
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateUi();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ getFragmentManager().popBackStack();
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void updateUi() {
+ if (getPreferenceScreen() != null) {
+ getPreferenceScreen().removeAll();
+ }
+ addPreferencesFromResource(R.xml.all_permissions);
+ PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER);
+ 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();
+
+ 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;
+ }
+
+ 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));
+ }
+ }
+ }
+ } 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
+ public int compare(Preference lhs, Preference rhs) {
+ String lKey = lhs.getKey();
+ String rKey = rhs.getKey();
+ if (lKey.equals(KEY_OTHER)) {
+ return 1;
+ } else if (rKey.equals(KEY_OTHER)) {
+ return -1;
+ } else if (Utils.isModernPermissionGroup(lKey)
+ != Utils.isModernPermissionGroup(rKey)) {
+ return Utils.isModernPermissionGroup(lKey) ? -1 : 1;
+ }
+ return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
+ }
+ });
+ for (int i = 0; i < prefs.size(); i++) {
+ prefs.get(i).setOrder(i);
+ }
+ }
+
+ private PermissionGroupInfo getGroup(String group, PackageManager pm) {
+ try {
+ return pm.getPermissionGroupInfo(group, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ private PreferenceGroup findOrCreate(PackageItemInfo group, PackageManager pm,
+ ArrayList<Preference> prefs) {
+ PreferenceGroup pref = (PreferenceGroup) findPreference(group.name);
+ if (pref == null) {
+ pref = new PreferenceCategory(getContext());
+ pref.setKey(group.name);
+ pref.setTitle(group.loadLabel(pm));
+ prefs.add(pref);
+ getPreferenceScreen().addPreference(pref);
+ }
+ return pref;
+ }
+
+ private Preference getPreference(PermissionInfo perm, PermissionGroupInfo group,
+ PackageManager pm) {
+ Preference pref = new Preference(getContext());
+ Drawable icon = null;
+ if (perm.icon != 0) {
+ icon = perm.loadIcon(pm);
+ } else if (group != null && group.icon != 0) {
+ icon = group.loadIcon(pm);
+ } else {
+ icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
+ }
+ pref.setIcon(Utils.applyTint(getContext(), icon, android.R.attr.colorControlNormal));
+ pref.setTitle(perm.loadLabel(pm));
+ final CharSequence desc = perm.loadDescription(pm);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ new AlertDialog.Builder(getContext())
+ .setMessage(desc)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ return true;
+ }
+ });
+
+ return pref;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java
new file mode 100644
index 00000000..f56cba70
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java
@@ -0,0 +1,404 @@
+/*
+* 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.handheld;
+
+import android.annotation.Nullable;
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+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.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
+import com.android.packageinstaller.permission.utils.LocationUtils;
+import com.android.packageinstaller.permission.utils.SafetyNetLogger;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class AppPermissionsFragment extends SettingsWithHeader
+ implements OnPreferenceChangeListener {
+
+ private static final String LOG_TAG = "ManagePermsFragment";
+
+ static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
+
+ private static final int MENU_ALL_PERMS = 0;
+
+ private List<AppPermissionGroup> mToggledGroups;
+ private AppPermissions mAppPermissions;
+ private PreferenceScreen mExtraScreen;
+
+ private boolean mHasConfirmedRevoke;
+
+ public static AppPermissionsFragment newInstance(String packageName) {
+ return setPackageName(new AppPermissionsFragment(), packageName);
+ }
+
+ private static <T extends Fragment> T setPackageName(T fragment, String packageName) {
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setLoading(true /* loading */, false /* animate */);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ Activity activity = getActivity();
+ PackageInfo packageInfo = getPackageInfo(activity, packageName);
+ if (packageInfo == null) {
+ Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
+ activity.finish();
+ return;
+ }
+
+ mAppPermissions = new AppPermissions(activity, packageInfo, null, true, new Runnable() {
+ @Override
+ public void run() {
+ getActivity().finish();
+ }
+ });
+ loadPreferences();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mAppPermissions.refresh();
+ setPreferencesCheckedState();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ getActivity().finish();
+ return true;
+ }
+
+ case MENU_ALL_PERMS: {
+ Fragment frag = AllAppPermissionsFragment.newInstance(
+ getArguments().getString(Intent.EXTRA_PACKAGE_NAME));
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack("AllPerms")
+ .commit();
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (mAppPermissions != null) {
+ bindUi(this, mAppPermissions.getPackageInfo());
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ menu.add(Menu.NONE, MENU_ALL_PERMS, Menu.NONE, R.string.all_permissions);
+ }
+
+ private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) {
+ Activity activity = fragment.getActivity();
+ PackageManager pm = activity.getPackageManager();
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+ Intent infoIntent = null;
+ if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) {
+ infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ .setData(Uri.fromParts("package", packageInfo.packageName, null));
+ }
+
+ Drawable icon = appInfo.loadIcon(pm);
+ CharSequence label = appInfo.loadLabel(pm);
+ fragment.setHeader(icon, label, infoIntent);
+
+ ActionBar ab = activity.getActionBar();
+ if (ab != null) {
+ ab.setTitle(R.string.app_permissions);
+ }
+
+ ViewGroup rootView = (ViewGroup) fragment.getView();
+ ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ iconView.setImageDrawable(icon);
+ }
+ TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(R.string.app_permissions);
+ }
+ TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(label);
+ }
+ }
+
+ private void loadPreferences() {
+ Context context = getActivity();
+ if (context == null) {
+ return;
+ }
+
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ }
+
+ screen.removeAll();
+
+ if (mExtraScreen != null) {
+ mExtraScreen.removeAll();
+ }
+
+ final Preference extraPerms = new Preference(context);
+ extraPerms.setIcon(R.drawable.ic_toc);
+ extraPerms.setTitle(R.string.additional_permissions);
+
+ for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ if (!Utils.shouldShowPermission(group, mAppPermissions.getPackageInfo().packageName)) {
+ continue;
+ }
+
+ boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
+
+ SwitchPreference preference = new SwitchPreference(context);
+ preference.setOnPreferenceChangeListener(this);
+ preference.setKey(group.getName());
+ Drawable icon = Utils.loadDrawable(context.getPackageManager(),
+ group.getIconPkg(), group.getIconResId());
+ preference.setIcon(Utils.applyTint(getContext(), icon,
+ android.R.attr.colorControlNormal));
+ preference.setTitle(group.getLabel());
+ if (group.isPolicyFixed()) {
+ preference.setSummary(getString(R.string.permission_summary_enforced_by_policy));
+ }
+ preference.setPersistent(false);
+ preference.setEnabled(!group.isPolicyFixed());
+ preference.setChecked(group.areRuntimePermissionsGranted());
+
+ if (isPlatform) {
+ screen.addPreference(preference);
+ } else {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ }
+ mExtraScreen.addPreference(preference);
+ }
+ }
+
+ if (mExtraScreen != null) {
+ extraPerms.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment();
+ setPackageName(frag, getArguments().getString(Intent.EXTRA_PACKAGE_NAME));
+ frag.setTargetFragment(AppPermissionsFragment.this, 0);
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack(null)
+ .commit();
+ return true;
+ }
+ });
+ int count = mExtraScreen.getPreferenceCount();
+ extraPerms.setSummary(getResources().getQuantityString(
+ R.plurals.additional_permissions_more, count, count));
+ screen.addPreference(extraPerms);
+ }
+
+ setLoading(false /* loading */, true /* animate */);
+ }
+
+ @Override
+ public boolean onPreferenceChange(final Preference preference, Object newValue) {
+ String groupName = preference.getKey();
+ final AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
+
+ if (group == null) {
+ return false;
+ }
+
+ OverlayTouchActivity activity = (OverlayTouchActivity) getActivity();
+ if (activity.isObscuredTouch()) {
+ activity.showOverlayDialog();
+ return false;
+ }
+
+ addToggledGroup(group);
+
+ if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) {
+ LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel());
+ return false;
+ }
+ if (newValue == Boolean.TRUE) {
+ group.grantRuntimePermissions(false);
+ } else {
+ final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
+ if (grantedByDefault || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) {
+ new AlertDialog.Builder(getContext())
+ .setMessage(grantedByDefault ? R.string.system_warning
+ : R.string.old_sdk_deny_warning)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.grant_dialog_button_deny,
+ new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((SwitchPreference) preference).setChecked(false);
+ group.revokeRuntimePermissions(false);
+ if (!grantedByDefault) {
+ mHasConfirmedRevoke = true;
+ }
+ }
+ })
+ .show();
+ return false;
+ } else {
+ group.revokeRuntimePermissions(false);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ logToggledGroups();
+ }
+
+ private void addToggledGroup(AppPermissionGroup group) {
+ if (mToggledGroups == null) {
+ mToggledGroups = new ArrayList<>();
+ }
+ // Double toggle is back to initial state.
+ if (mToggledGroups.contains(group)) {
+ mToggledGroups.remove(group);
+ } else {
+ mToggledGroups.add(group);
+ }
+ }
+
+ private void logToggledGroups() {
+ if (mToggledGroups != null) {
+ String packageName = mAppPermissions.getPackageInfo().packageName;
+ SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
+ mToggledGroups = null;
+ }
+ }
+
+ private void setPreferencesCheckedState() {
+ setPreferencesCheckedState(getPreferenceScreen());
+ if (mExtraScreen != null) {
+ setPreferencesCheckedState(mExtraScreen);
+ }
+ }
+
+ private void setPreferencesCheckedState(PreferenceScreen screen) {
+ int preferenceCount = screen.getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ Preference preference = screen.getPreference(i);
+ if (preference instanceof SwitchPreference) {
+ SwitchPreference switchPref = (SwitchPreference) preference;
+ AppPermissionGroup group = mAppPermissions.getPermissionGroup(switchPref.getKey());
+ if (group != null) {
+ switchPref.setChecked(group.areRuntimePermissionsGranted());
+ }
+ }
+ }
+ }
+
+ private static PackageInfo getPackageInfo(Activity activity, String packageName) {
+ try {
+ return activity.getPackageManager().getPackageInfo(
+ packageName, PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
+ return null;
+ }
+ }
+
+ public static class AdditionalPermissionsFragment extends SettingsWithHeader {
+ AppPermissionsFragment mOuterFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mOuterFragment = (AppPermissionsFragment) getTargetFragment();
+ super.onCreate(savedInstanceState);
+ setHeader(mOuterFragment.mIcon, mOuterFragment.mLabel, mOuterFragment.mInfoIntent);
+ setHasOptionsMenu(true);
+ setPreferenceScreen(mOuterFragment.mExtraScreen);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
+ bindUi(this, getPackageInfo(getActivity(), packageName));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getFragmentManager().popBackStack();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsDefaultViewHandler.java b/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
index c5d78784..2d27f069 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsDefaultViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.handheld;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -40,12 +40,14 @@ import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.internal.widget.ButtonBarLayout;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.ui.ButtonBarLayout;
+import com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler;
+import com.android.packageinstaller.permission.ui.ManualLayoutFrame;
import java.util.ArrayList;
-final class GrantPermissionsDefaultViewHandler
+public final class GrantPermissionsViewHandlerImpl
implements GrantPermissionsViewHandler, OnClickListener {
public static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
@@ -101,12 +103,12 @@ final class GrantPermissionsDefaultViewHandler
}
};
- GrantPermissionsDefaultViewHandler(Context context) {
+ public GrantPermissionsViewHandlerImpl(Context context) {
mContext = context;
}
@Override
- public GrantPermissionsDefaultViewHandler setResultListener(ResultListener listener) {
+ public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) {
mResultListener = listener;
return this;
}
@@ -314,9 +316,7 @@ final class GrantPermissionsDefaultViewHandler
public View createView() {
mRootView = (ManualLayoutFrame) LayoutInflater.from(mContext)
.inflate(R.layout.grant_permissions, null);
- ((ButtonBarLayout) mRootView.findViewById(R.id.button_group)).setAllowStacking(
- Resources.getSystem().getBoolean(
- com.android.internal.R.bool.allow_stacked_button_bar));
+ ((ButtonBarLayout) mRootView.findViewById(R.id.button_group)).setAllowStacking(true);
mDialogContainer = (ViewGroup) mRootView.findViewById(R.id.dialog_container);
mMessageView = (TextView) mRootView.findViewById(R.id.permission_message);
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java
new file mode 100644
index 00000000..c53da879
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/ManagePermissionsFragment.java
@@ -0,0 +1,268 @@
+/*
+ * 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.handheld;
+
+import android.annotation.Nullable;
+import android.app.ActionBar;
+import android.app.FragmentTransaction;
+import android.content.ActivityNotFoundException;
+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.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.View;
+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.PmCache;
+import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.model.PermissionGroups;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.List;
+
+public final class ManagePermissionsFragment extends PermissionsFrameFragment
+ implements PermissionGroups.PermissionsGroupsChangeCallback,
+ Preference.OnPreferenceClickListener {
+ private static final String LOG_TAG = "ManagePermissionsFragment";
+
+ private static final String OS_PKG = "android";
+
+ private static final String EXTRA_PREFS_KEY = "extra_prefs_key";
+
+ private ArraySet<String> mLauncherPkgs;
+
+ private PermissionGroups mPermissions;
+
+ private PreferenceScreen mExtraScreen;
+
+ public static ManagePermissionsFragment newInstance() {
+ return new ManagePermissionsFragment();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setLoading(true /* loading */, false /* animate */);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ mLauncherPkgs = Utils.getLauncherPackages(getContext());
+ mPermissions = new PermissionGroups(getActivity(), getLoaderManager(), this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPermissions.refresh();
+ updatePermissionsUi();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ getActivity().finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ String key = preference.getKey();
+
+ PermissionGroup group = mPermissions.getGroup(key);
+ if (group == null) {
+ return false;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
+ .putExtra(Intent.EXTRA_PERMISSION_NAME, key);
+ try {
+ getActivity().startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(LOG_TAG, "No app to handle " + intent);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onPermissionGroupsChanged() {
+ updatePermissionsUi();
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindPermissionUi(getActivity(), getView());
+ }
+
+ private static void bindPermissionUi(@Nullable Context context, @Nullable View rootView) {
+ if (context == null || rootView == null) {
+ return;
+ }
+
+ ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ // Set the icon as the background instead of the image because ImageView
+ // doesn't properly scale vector drawables beyond their intrinsic size
+ Drawable icon = context.getDrawable(R.drawable.ic_lock);
+ icon.setTint(context.getColor(R.color.off_white));
+ iconView.setBackground(icon);
+ }
+ TextView titleView = (TextView) rootView.findViewById(R.id.lb_title);
+ if (titleView != null) {
+ titleView.setText(R.string.app_permissions);
+ }
+ TextView breadcrumbView = (TextView) rootView.findViewById(R.id.lb_breadcrumb);
+ if (breadcrumbView != null) {
+ breadcrumbView.setText(R.string.app_permissions_breadcrumb);
+ }
+ }
+
+ private void updatePermissionsUi() {
+ Context context = getActivity();
+ if (context == null) {
+ return;
+ }
+
+ List<PermissionGroup> groups = mPermissions.getGroups();
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ }
+
+ // Use this to speed up getting the info for all of the PermissionApps below.
+ // Create a new one for each refresh to make sure it has fresh data.
+ PmCache cache = new PmCache(getContext().getPackageManager());
+ for (PermissionGroup group : groups) {
+ boolean isSystemPermission = group.getDeclaringPackage().equals(OS_PKG);
+
+ Preference preference = findPreference(group.getName());
+ if (preference == null && mExtraScreen != null) {
+ preference = mExtraScreen.findPreference(group.getName());
+ }
+ if (preference == null) {
+ preference = new Preference(context);
+ preference.setOnPreferenceClickListener(this);
+ preference.setKey(group.getName());
+ preference.setIcon(Utils.applyTint(context, group.getIcon(),
+ android.R.attr.colorControlNormal));
+ preference.setTitle(group.getLabel());
+ // Set blank summary so that no resizing/jumping happens when the summary is loaded.
+ preference.setSummary(" ");
+ preference.setPersistent(false);
+ if (isSystemPermission) {
+ screen.addPreference(preference);
+ } else {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ }
+ mExtraScreen.addPreference(preference);
+ }
+ }
+ final Preference finalPref = preference;
+
+ new PermissionApps(getContext(), group.getName(), new PermissionApps.Callback() {
+ @Override
+ public void onPermissionsLoaded(PermissionApps permissionApps) {
+ if (getActivity() == null) {
+ return;
+ }
+ int granted = permissionApps.getGrantedCount(mLauncherPkgs);
+ int total = permissionApps.getTotalCount(mLauncherPkgs);
+ finalPref.setSummary(getString(R.string.app_permissions_group_summary,
+ granted, total));
+ }
+ }, cache).refresh(false);
+ }
+
+ if (mExtraScreen != null && mExtraScreen.getPreferenceCount() > 0
+ && screen.findPreference(EXTRA_PREFS_KEY) == null) {
+ Preference extraScreenPreference = new Preference(context);
+ extraScreenPreference.setKey(EXTRA_PREFS_KEY);
+ extraScreenPreference.setIcon(Utils.applyTint(context,
+ R.drawable.ic_more_items,
+ android.R.attr.colorControlNormal));
+ extraScreenPreference.setTitle(R.string.additional_permissions);
+ extraScreenPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment();
+ frag.setTargetFragment(ManagePermissionsFragment.this, 0);
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(android.R.id.content, frag);
+ ft.addToBackStack(null);
+ ft.commit();
+ return true;
+ }
+ });
+ int count = mExtraScreen.getPreferenceCount();
+ extraScreenPreference.setSummary(getResources().getQuantityString(
+ R.plurals.additional_permissions_more, count, count));
+ screen.addPreference(extraScreenPreference);
+ }
+ if (screen.getPreferenceCount() != 0) {
+ setLoading(false /* loading */, true /* animate */);
+ }
+ }
+
+ public static class AdditionalPermissionsFragment extends PermissionsFrameFragment {
+ @Override
+ public void onCreate(Bundle icicle) {
+ setLoading(true /* loading */, false /* animate */);
+ super.onCreate(icicle);
+ getActivity().setTitle(R.string.additional_permissions);
+ setHasOptionsMenu(true);
+
+ setPreferenceScreen(((ManagePermissionsFragment) getTargetFragment()).mExtraScreen);
+ setLoading(false /* loading */, true /* animate */);
+ }
+
+ @Override
+ public void onDestroy() {
+ getActivity().setTitle(R.string.app_permissions);
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getFragmentManager().popBackStack();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindPermissionUi(getActivity(), getView());
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
new file mode 100644
index 00000000..554830a7
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
@@ -0,0 +1,427 @@
+/*
+ * 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.handheld;
+
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.view.Menu;
+import android.view.MenuInflater;
+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.AppPermissionGroup;
+import com.android.packageinstaller.permission.model.PermissionApps;
+import com.android.packageinstaller.permission.model.PermissionApps.Callback;
+import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
+import com.android.packageinstaller.permission.utils.LocationUtils;
+import com.android.packageinstaller.permission.utils.SafetyNetLogger;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class PermissionAppsFragment extends PermissionsFrameFragment implements Callback,
+ Preference.OnPreferenceChangeListener {
+
+ private static final int MENU_SHOW_SYSTEM = Menu.FIRST;
+ private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 1;
+ private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem";
+
+ public static PermissionAppsFragment newInstance(String permissionName) {
+ return setPermissionName(new PermissionAppsFragment(), permissionName);
+ }
+
+ private static <T extends Fragment> T setPermissionName(T fragment, String permissionName) {
+ Bundle arguments = new Bundle();
+ arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ private PermissionApps mPermissionApps;
+
+ private PreferenceScreen mExtraScreen;
+
+ private ArrayMap<String, AppPermissionGroup> mToggledGroups;
+ private ArraySet<String> mLauncherPkgs;
+ private boolean mHasConfirmedRevoke;
+
+ private boolean mShowSystem;
+ private MenuItem mShowSystemMenu;
+ private MenuItem mHideSystemMenu;
+
+ private Callback mOnPermissionsLoadedListener;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setLoading(true /* loading */, false /* animate */);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ mLauncherPkgs = Utils.getLauncherPackages(getContext());
+
+ String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
+ mPermissionApps = new PermissionApps(getActivity(), groupName, this);
+ mPermissionApps.refresh(true);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPermissionApps.refresh(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ mShowSystemMenu = menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
+ R.string.menu_show_system);
+ mHideSystemMenu = menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE,
+ R.string.menu_hide_system);
+ updateMenu();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getActivity().finish();
+ return true;
+ case MENU_SHOW_SYSTEM:
+ case MENU_HIDE_SYSTEM:
+ mShowSystem = item.getItemId() == MENU_SHOW_SYSTEM;
+ if (mPermissionApps.getApps() != null) {
+ onPermissionsLoaded(mPermissionApps);
+ }
+ updateMenu();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void updateMenu() {
+ mShowSystemMenu.setVisible(!mShowSystem);
+ mHideSystemMenu.setVisible(mShowSystem);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ bindUi(this, mPermissionApps);
+ }
+
+ private static void bindUi(Fragment fragment, PermissionApps permissionApps) {
+ final Drawable icon = permissionApps.getIcon();
+ final CharSequence label = permissionApps.getLabel();
+ final ActionBar ab = fragment.getActivity().getActionBar();
+ if (ab != null) {
+ ab.setTitle(fragment.getString(R.string.permission_title, label));
+ }
+
+ final ViewGroup rootView = (ViewGroup) fragment.getView();
+ final ImageView iconView = (ImageView) rootView.findViewById(R.id.lb_icon);
+ if (iconView != null) {
+ // Set the icon as the background instead of the image because ImageView
+ // doesn't properly scale vector drawables beyond their intrinsic size
+ iconView.setBackground(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);
+ }
+ }
+
+ private void setOnPermissionsLoadedListener(Callback callback) {
+ mOnPermissionsLoadedListener = callback;
+ }
+
+ @Override
+ public void onPermissionsLoaded(PermissionApps permissionApps) {
+ Context context = getActivity();
+
+ if (context == null) {
+ return;
+ }
+
+ boolean isTelevision = Utils.isTelevision(context);
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(screen);
+ }
+
+ ArraySet<String> preferencesToRemove = new ArraySet<>();
+ for (int i = 0, n = screen.getPreferenceCount(); i < n; i++) {
+ preferencesToRemove.add(screen.getPreference(i).getKey());
+ }
+ if (mExtraScreen != null) {
+ for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) {
+ preferencesToRemove.add(mExtraScreen.getPreference(i).getKey());
+ }
+ }
+
+ for (PermissionApp app : permissionApps.getApps()) {
+ if (!Utils.shouldShowPermission(app)) {
+ continue;
+ }
+
+ String key = app.getKey();
+ preferencesToRemove.remove(key);
+ Preference existingPref = screen.findPreference(key);
+ if (existingPref == null && mExtraScreen != null) {
+ existingPref = mExtraScreen.findPreference(key);
+ }
+
+ boolean isSystemApp = Utils.isSystem(app, mLauncherPkgs);
+ if (isSystemApp && !isTelevision && !mShowSystem) {
+ if (existingPref != null) {
+ screen.removePreference(existingPref);
+ }
+ continue;
+ }
+
+ if (existingPref != null) {
+ // If existing preference - only update its state.
+ if (app.isPolicyFixed()) {
+ existingPref.setSummary(getString(
+ R.string.permission_summary_enforced_by_policy));
+ }
+ existingPref.setPersistent(false);
+ existingPref.setEnabled(!app.isPolicyFixed());
+ if (existingPref instanceof SwitchPreference) {
+ ((SwitchPreference) existingPref)
+ .setChecked(app.areRuntimePermissionsGranted());
+ }
+ continue;
+ }
+
+ SwitchPreference pref = new SwitchPreference(context);
+ pref.setOnPreferenceChangeListener(this);
+ pref.setKey(app.getKey());
+ pref.setIcon(app.getIcon());
+ pref.setTitle(app.getLabel());
+ if (app.isPolicyFixed()) {
+ pref.setSummary(getString(R.string.permission_summary_enforced_by_policy));
+ }
+ pref.setPersistent(false);
+ pref.setEnabled(!app.isPolicyFixed());
+ pref.setChecked(app.areRuntimePermissionsGranted());
+
+ if (isSystemApp && isTelevision) {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
+ }
+ mExtraScreen.addPreference(pref);
+ } else {
+ screen.addPreference(pref);
+ }
+ }
+
+ if (mExtraScreen != null) {
+ preferencesToRemove.remove(KEY_SHOW_SYSTEM_PREFS);
+ Preference pref = screen.findPreference(KEY_SHOW_SYSTEM_PREFS);
+
+ if (pref == null) {
+ pref = new Preference(context);
+ pref.setKey(KEY_SHOW_SYSTEM_PREFS);
+ pref.setIcon(Utils.applyTint(context, R.drawable.ic_toc,
+ android.R.attr.colorControlNormal));
+ pref.setTitle(R.string.preference_show_system_apps);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ SystemAppsFragment frag = new SystemAppsFragment();
+ setPermissionName(frag, getArguments().getString(Intent.EXTRA_PERMISSION_NAME));
+ frag.setTargetFragment(PermissionAppsFragment.this, 0);
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack("SystemApps")
+ .commit();
+ return true;
+ }
+ });
+ screen.addPreference(pref);
+ }
+
+ int grantedCount = 0;
+ for (int i = 0, n = mExtraScreen.getPreferenceCount(); i < n; i++) {
+ if (((SwitchPreference) mExtraScreen.getPreference(i)).isChecked()) {
+ grantedCount++;
+ }
+ }
+ pref.setSummary(getString(R.string.app_permissions_group_summary,
+ grantedCount, mExtraScreen.getPreferenceCount()));
+ }
+
+ for (String key : preferencesToRemove) {
+ Preference pref = screen.findPreference(key);
+ if (pref != null) {
+ screen.removePreference(pref);
+ } else if (mExtraScreen != null) {
+ pref = mExtraScreen.findPreference(key);
+ if (pref != null) {
+ mExtraScreen.removePreference(pref);
+ }
+ }
+ }
+
+ setLoading(false /* loading */, true /* animate */);
+
+ if (mOnPermissionsLoadedListener != null) {
+ mOnPermissionsLoadedListener.onPermissionsLoaded(permissionApps);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(final Preference preference, Object newValue) {
+ String pkg = preference.getKey();
+ final PermissionApp app = mPermissionApps.getApp(pkg);
+
+ if (app == null) {
+ return false;
+ }
+
+ OverlayTouchActivity activity = (OverlayTouchActivity) getActivity();
+ if (activity.isObscuredTouch()) {
+ activity.showOverlayDialog();
+ return false;
+ }
+
+ addToggledGroup(app.getPackageName(), app.getPermissionGroup());
+
+ if (LocationUtils.isLocationGroupAndProvider(mPermissionApps.getGroupName(),
+ app.getPackageName())) {
+ LocationUtils.showLocationDialog(getContext(), app.getLabel());
+ return false;
+ }
+ if (newValue == Boolean.TRUE) {
+ app.grantRuntimePermissions();
+ } else {
+ final boolean grantedByDefault = app.hasGrantedByDefaultPermissions();
+ if (grantedByDefault || (!app.hasRuntimePermissions() && !mHasConfirmedRevoke)) {
+ new AlertDialog.Builder(getContext())
+ .setMessage(grantedByDefault ? R.string.system_warning
+ : R.string.old_sdk_deny_warning)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.grant_dialog_button_deny,
+ new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((SwitchPreference) preference).setChecked(false);
+ app.revokeRuntimePermissions();
+ if (!grantedByDefault) {
+ mHasConfirmedRevoke = true;
+ }
+ }
+ })
+ .show();
+ return false;
+ } else {
+ app.revokeRuntimePermissions();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ logToggledGroups();
+ }
+
+ private void addToggledGroup(String packageName, AppPermissionGroup group) {
+ if (mToggledGroups == null) {
+ mToggledGroups = new ArrayMap<>();
+ }
+ // Double toggle is back to initial state.
+ if (mToggledGroups.containsKey(packageName)) {
+ mToggledGroups.remove(packageName);
+ } else {
+ mToggledGroups.put(packageName, group);
+ }
+ }
+
+ private void logToggledGroups() {
+ if (mToggledGroups != null) {
+ final int groupCount = mToggledGroups.size();
+ for (int i = 0; i < groupCount; i++) {
+ String packageName = mToggledGroups.keyAt(i);
+ List<AppPermissionGroup> groups = new ArrayList<>();
+ groups.add(mToggledGroups.valueAt(i));
+ SafetyNetLogger.logPermissionsToggled(packageName, groups);
+ }
+ mToggledGroups = null;
+ }
+ }
+
+ public static class SystemAppsFragment extends PermissionsFrameFragment implements Callback {
+ PermissionAppsFragment mOuterFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mOuterFragment = (PermissionAppsFragment) getTargetFragment();
+ setLoading(true /* loading */, false /* animate */);
+ super.onCreate(savedInstanceState);
+ if (mOuterFragment.mExtraScreen != null) {
+ setPreferenceScreen();
+ } else {
+ mOuterFragment.setOnPermissionsLoadedListener(this);
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
+ PermissionApps permissionApps = new PermissionApps(getActivity(), groupName, null);
+ bindUi(this, permissionApps);
+ }
+
+ @Override
+ public void onPermissionsLoaded(PermissionApps permissionApps) {
+ setPreferenceScreen();
+ mOuterFragment.setOnPermissionsLoadedListener(null);
+ }
+
+ private void setPreferenceScreen() {
+ setPreferenceScreen(mOuterFragment.mExtraScreen);
+ setLoading(false /* loading */, true /* animate */);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java
new file mode 100644
index 00000000..e7f63b23
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionsFrameFragment.java
@@ -0,0 +1,121 @@
+/*
+ * 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.handheld;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.packageinstaller.R;
+
+public abstract class PermissionsFrameFragment extends PreferenceFragment {
+ private ViewGroup mPreferencesContainer;
+
+ private View mLoadingView;
+ private ViewGroup mPrefsView;
+ private boolean mIsLoading;
+
+ /**
+ * Returns the view group that holds the preferences objects. This will
+ * only be set after {@link #onCreateView} has been called.
+ */
+ protected final ViewGroup getPreferencesContainer() {
+ return mPreferencesContainer;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container,
+ false);
+ mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container);
+ if (mPrefsView == null) {
+ mPrefsView = rootView;
+ }
+ mLoadingView = rootView.findViewById(R.id.loading_container);
+ mPreferencesContainer = (ViewGroup) super.onCreateView(
+ inflater, mPrefsView, savedInstanceState);
+ setLoading(mIsLoading, false, true /* force */);
+ mPrefsView.addView(mPreferencesContainer);
+ return rootView;
+ }
+
+ protected void setLoading(boolean loading, boolean animate) {
+ setLoading(loading, animate, false);
+ }
+
+ private void setLoading(boolean loading, boolean animate, boolean force) {
+ if (mIsLoading != loading || force) {
+ mIsLoading = loading;
+ if (getView() == null) {
+ // If there is no created view, there is no reason to animate.
+ animate = false;
+ }
+ if (mPrefsView != null) {
+ setViewShown(mPrefsView, !loading, animate);
+ }
+ if (mLoadingView != null) {
+ setViewShown(mLoadingView, loading, animate);
+ }
+ }
+ }
+
+ @Override
+ public ListView getListView() {
+ ListView listView = super.getListView();
+ if (listView.getEmptyView() == null) {
+ TextView emptyView = (TextView) getView().findViewById(R.id.no_permissions);
+ listView.setEmptyView(emptyView);
+ }
+ return listView;
+ }
+
+ private void setViewShown(final View view, boolean shown, boolean animate) {
+ if (animate) {
+ Animation animation = AnimationUtils.loadAnimation(getContext(),
+ shown ? android.R.anim.fade_in : android.R.anim.fade_out);
+ if (shown) {
+ view.setVisibility(View.VISIBLE);
+ } else {
+ animation.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ view.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ view.startAnimation(animation);
+ } else {
+ view.clearAnimation();
+ view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java b/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java
new file mode 100644
index 00000000..acb3c61e
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/handheld/SettingsWithHeader.java
@@ -0,0 +1,84 @@
+/*
+ * 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.handheld;
+
+import android.content.Intent;
+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 abstract class SettingsWithHeader extends PermissionsFrameFragment
+ implements OnClickListener {
+
+ private View mHeader;
+ protected Intent mInfoIntent;
+ protected Drawable mIcon;
+ protected CharSequence mLabel;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
+
+ if (!Utils.isTelevision(getContext())) {
+ mHeader = inflater.inflate(R.layout.header, root, false);
+ getPreferencesContainer().addView(mHeader, 0);
+ updateHeader();
+ }
+
+ return root;
+ }
+
+ 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.setVisibility(View.VISIBLE);
+ info.setClickable(true);
+ info.setOnClickListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ getActivity().startActivity(mInfoIntent);
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/AllAppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
index 2fb9a510..d4910128 100644
--- a/src/com/android/packageinstaller/permission/ui/AllAppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/AllAppPermissionsFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.app.ActionBar;
import android.app.AlertDialog;
diff --git a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
index 6396c61e..42a2661c 100644
--- a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/AppPermissionsFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.annotation.Nullable;
import android.app.ActionBar;
@@ -50,6 +50,7 @@ import android.widget.Toast;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
import com.android.packageinstaller.permission.utils.LocationUtils;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsTvViewHandler.java b/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
index 0e979ab6..a2538821 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsTvViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
@@ -1,4 +1,4 @@
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.content.Context;
import android.graphics.PixelFormat;
@@ -15,11 +15,12 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler;
/**
* TV-specific view handler for the grant permissions activity.
*/
-final class GrantPermissionsTvViewHandler implements GrantPermissionsViewHandler, OnClickListener {
+public final class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler, OnClickListener {
private static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
@@ -37,12 +38,12 @@ final class GrantPermissionsTvViewHandler implements GrantPermissionsViewHandler
private Button mSoftDenyButton;
private Button mHardDenyButton;
- GrantPermissionsTvViewHandler(Context context) {
+ public GrantPermissionsViewHandlerImpl(Context context) {
mContext = context;
}
@Override
- public GrantPermissionsTvViewHandler setResultListener(ResultListener listener) {
+ public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) {
mResultListener = listener;
return this;
}
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java
index e5e06e09..47301f48 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/ManagePermissionsFragment.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.annotation.Nullable;
import android.app.ActionBar;
@@ -202,7 +202,7 @@ public final class ManagePermissionsFragment extends PermissionsFrameFragment
Preference extraScreenPreference = new Preference(context);
extraScreenPreference.setKey(EXTRA_PREFS_KEY);
extraScreenPreference.setIcon(Utils.applyTint(context,
- com.android.internal.R.drawable.ic_more_items,
+ R.drawable.ic_more_items,
android.R.attr.colorControlNormal));
extraScreenPreference.setTitle(R.string.additional_permissions);
extraScreenPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
diff --git a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
index 1e588939..0f240bef 100644
--- a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionAppsFragment.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.packageinstaller.permission.ui;
+package com.android.packageinstaller.permission.ui.television;
import android.app.ActionBar;
import android.app.AlertDialog;
@@ -45,6 +45,7 @@ import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.PermissionApps;
import com.android.packageinstaller.permission.model.PermissionApps.Callback;
import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+import com.android.packageinstaller.permission.ui.OverlayTouchActivity;
import com.android.packageinstaller.permission.utils.LocationUtils;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;
diff --git a/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java b/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java
new file mode 100644
index 00000000..bc0e8457
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/television/PermissionsFrameFragment.java
@@ -0,0 +1,203 @@
+/*
+ * 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.television;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.utils.Utils;
+
+public abstract class PermissionsFrameFragment extends PreferenceFragment {
+
+ private static final float WINDOW_ALIGNMENT_OFFSET_PERCENT = 50;
+
+ private ViewGroup mPreferencesContainer;
+
+ // TV-specific instance variables
+ @Nullable private VerticalGridView mGridView;
+
+ private View mLoadingView;
+ private ViewGroup mPrefsView;
+ private boolean mIsLoading;
+
+ /**
+ * Returns the view group that holds the preferences objects. This will
+ * only be set after {@link #onCreateView} has been called.
+ */
+ protected final ViewGroup getPreferencesContainer() {
+ return mPreferencesContainer;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container,
+ false);
+ mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container);
+ if (mPrefsView == null) {
+ mPrefsView = rootView;
+ }
+ mLoadingView = rootView.findViewById(R.id.loading_container);
+ mPreferencesContainer = (ViewGroup) super.onCreateView(
+ inflater, mPrefsView, savedInstanceState);
+ setLoading(mIsLoading, false, true /* force */);
+ mPrefsView.addView(mPreferencesContainer);
+ return rootView;
+ }
+
+ @Override
+ public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
+ PreferenceScreen preferences = getPreferenceScreen();
+ if (preferences == null) {
+ preferences = getPreferenceManager().createPreferenceScreen(getActivity());
+ setPreferenceScreen(preferences);
+ }
+ }
+
+ protected void setLoading(boolean loading, boolean animate) {
+ setLoading(loading, animate, false);
+ }
+
+ private void setLoading(boolean loading, boolean animate, boolean force) {
+ if (mIsLoading != loading || force) {
+ mIsLoading = loading;
+ if (getView() == null) {
+ // If there is no created view, there is no reason to animate.
+ animate = false;
+ }
+ if (mPrefsView != null) {
+ setViewShown(mPrefsView, !loading, animate);
+ }
+ if (mLoadingView != null) {
+ setViewShown(mLoadingView, loading, animate);
+ }
+ }
+ }
+
+ private void setViewShown(final View view, boolean shown, boolean animate) {
+ if (animate) {
+ Animation animation = AnimationUtils.loadAnimation(getContext(),
+ shown ? android.R.anim.fade_in : android.R.anim.fade_out);
+ if (shown) {
+ view.setVisibility(View.VISIBLE);
+ } else {
+ animation.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ view.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ view.startAnimation(animation);
+ } else {
+ view.clearAnimation();
+ view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+ Bundle savedInstanceState) {
+ if (Utils.isTelevision(getContext())) {
+ mGridView = (VerticalGridView) inflater.inflate(
+ R.layout.leanback_preferences_list, parent, false);
+ mGridView.setWindowAlignmentOffset(0);
+ mGridView.setWindowAlignmentOffsetPercent(WINDOW_ALIGNMENT_OFFSET_PERCENT);
+ mGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
+ mGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED);
+ return mGridView;
+ } else {
+ return super.onCreateRecyclerView(inflater, parent, savedInstanceState);
+ }
+ }
+
+ @Override
+ protected RecyclerView.Adapter<?> onCreateAdapter(PreferenceScreen preferenceScreen) {
+ final RecyclerView.Adapter<?> adapter = super.onCreateAdapter(preferenceScreen);
+
+ if (adapter != null) {
+ final TextView emptyView = (TextView) getView().findViewById(R.id.no_permissions);
+ onSetEmptyText(emptyView);
+ final RecyclerView recyclerView = getListView();
+ adapter.registerAdapterDataObserver(new AdapterDataObserver() {
+ @Override
+ public void onChanged() {
+ checkEmpty();
+ }
+
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ checkEmpty();
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ checkEmpty();
+ }
+
+ private void checkEmpty() {
+ boolean isEmpty = adapter.getItemCount() == 0;
+ emptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
+ recyclerView.setVisibility(isEmpty ? View.GONE : View.VISIBLE);
+ if (!isEmpty && mGridView != null) {
+ mGridView.requestFocus();
+ }
+ }
+ });
+
+ boolean isEmpty = adapter.getItemCount() == 0;
+ emptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
+ recyclerView.setVisibility(isEmpty ? View.GONE : View.VISIBLE);
+ if (!isEmpty && mGridView != null) {
+ mGridView.requestFocus();
+ }
+ }
+
+ return adapter;
+ }
+
+ /**
+ * Hook for subclasses to change the default text of the empty view.
+ * Base implementation leaves the default empty view text.
+ *
+ * @param textView the empty text view
+ */
+ protected void onSetEmptyText(TextView textView) {
+ }
+}
+
diff --git a/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java b/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java
new file mode 100644
index 00000000..c7f5cda3
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/television/SettingsWithHeader.java
@@ -0,0 +1,85 @@
+/*
+ * 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.television;
+
+import android.content.Intent;
+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 abstract class SettingsWithHeader extends PermissionsFrameFragment
+ implements OnClickListener {
+
+ private View mHeader;
+ protected Intent mInfoIntent;
+ protected Drawable mIcon;
+ protected CharSequence mLabel;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
+
+ if (!Utils.isTelevision(getContext())) {
+ mHeader = inflater.inflate(R.layout.header, root, false);
+ getPreferencesContainer().addView(mHeader, 0);
+ updateHeader();
+ }
+
+ return root;
+ }
+
+ 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.setVisibility(View.VISIBLE);
+ info.setClickable(true);
+ info.setOnClickListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ getActivity().startActivity(mInfoIntent);
+ }
+
+}
diff --git a/src/com/android/packageinstaller/permission/utils/LocationUtils.java b/src/com/android/packageinstaller/permission/utils/LocationUtils.java
index 512fcf44..0296ae80 100644
--- a/src/com/android/packageinstaller/permission/utils/LocationUtils.java
+++ b/src/com/android/packageinstaller/permission/utils/LocationUtils.java
@@ -36,23 +36,9 @@ public class LocationUtils {
public static final String LOCATION_PERMISSION = Manifest.permission_group.LOCATION;
- public static ArrayList<String> getLocationProviders() {
- ArrayList<String> providers = new ArrayList<>();
- Resources res = Resources.getSystem();
- providers.add(res.getString(
- com.android.internal.R.string.config_networkLocationProviderPackageName));
-
- for (String provider :
- res.getStringArray(com.android.internal.R.array.config_locationProviderPackageNames)) {
- providers.add(provider);
- }
-
- return providers;
- }
-
public static void showLocationDialog(final Context context, CharSequence label) {
new AlertDialog.Builder(context)
- .setIcon(com.android.internal.R.drawable.ic_dialog_alert_material)
+ .setIcon(R.drawable.ic_dialog_alert_material)
.setTitle(android.R.string.dialog_alert_title)
.setMessage(context.getString(R.string.location_warning, label))
.setNegativeButton(R.string.ok, null)
@@ -83,5 +69,4 @@ public class LocationUtils {
return false;
}
}
-
}