Merge branch 'permissions-ui' into 'master'

Permissions UI in AppDetails

* Removes the "m" prefix and some unnecessary TODOs
* Re-uses the permission list from the privileged installer for the list in AppDetails:

![device-2016-06-09-234253](/uploads/0f3807f05084e763c07c9b4b7c49c481/device-2016-06-09-234253.png)

See merge request !332
This commit is contained in:
Daniel Martí 2016-06-13 18:37:33 +00:00
commit 6b18ab4204
9 changed files with 156 additions and 216 deletions

View File

@ -90,8 +90,9 @@ import org.fdroid.fdroid.installer.InstallerFactory;
import org.fdroid.fdroid.installer.InstallerService;
import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.privileged.views.AppDiff;
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
import java.util.ArrayList;
import java.util.List;
public class AppDetails extends AppCompatActivity {
@ -1062,7 +1063,7 @@ public class AppDetails extends AppCompatActivity {
private final View.OnClickListener expanderPermissions = new View.OnClickListener() {
@Override
public void onClick(View v) {
final TextView permissionListView = (TextView) llViewMorePermissions.findViewById(R.id.permissions_list);
final View permissionListView = llViewMorePermissions.findViewById(R.id.permission_list);
final TextView permissionHeader = (TextView) llViewMorePermissions.findViewById(R.id.permissions);
if (permissionListView.getVisibility() == View.GONE) {
@ -1372,29 +1373,11 @@ public class AppDetails extends AppCompatActivity {
}
private void buildPermissionInfo() {
final TextView permissionListView = (TextView) llViewMorePermissions.findViewById(R.id.permissions_list);
AppDiff appDiff = new AppDiff(appDetails.getPackageManager(), appDetails.getApks().getItem(0));
AppSecurityPermissions perms = new AppSecurityPermissions(appDetails, appDiff.pkgInfo);
ArrayList<String> permsList = appDetails.getApks().getItem(0).getFullPermissionList();
if (permsList == null) {
permissionListView.setText(R.string.no_permissions);
} else {
StringBuilder sb = new StringBuilder();
for (String permissionName : permsList) {
try {
final Permission permission = new Permission(getActivity(), permissionName);
// TODO: Make this list RTL friendly
sb.append("\t• ").append(permission.getName()).append('\n');
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Permission not yet available: " + permissionName);
}
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
permissionListView.setText(sb.toString());
} else {
permissionListView.setText(R.string.no_permissions);
}
}
final ViewGroup permList = (ViewGroup) llViewMorePermissions.findViewById(R.id.permission_list);
permList.addView(perms.getPermissionsView(AppSecurityPermissions.WHICH_ALL));
}
private String descAntiFeature(String af) {

View File

@ -1,24 +0,0 @@
package org.fdroid.fdroid;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
public class Permission {
private final PackageManager packageManager;
private final PermissionInfo permissionInfo;
Permission(Context context, String permission)
throws PackageManager.NameNotFoundException {
this.packageManager = context.getPackageManager();
this.permissionInfo = this.packageManager.getPermissionInfo(
permission, PackageManager.GET_META_DATA);
}
public CharSequence getName() {
String label = this.permissionInfo.loadLabel(this.packageManager).toString();
return Character.toUpperCase(label.charAt(0)) + label.substring(1);
}
}

View File

@ -111,19 +111,19 @@ public abstract class Installer {
private int newPermissionCount(Apk apk) {
// TODO: requires targetSdk in Apk class/database
//boolean supportsRuntimePermissions = mPkgInfo.applicationInfo.targetSdkVersion
//boolean supportsRuntimePermissions = pkgInfo.applicationInfo.targetSdkVersion
// >= Build.VERSION_CODES.M;
//if (supportsRuntimePermissions) {
// return 0;
//}
AppDiff appDiff = new AppDiff(context.getPackageManager(), apk);
if (appDiff.mPkgInfo == null) {
if (appDiff.pkgInfo == null) {
// could not get diff because we couldn't parse the package
throw new RuntimeException("cannot parse!");
}
AppSecurityPermissions perms = new AppSecurityPermissions(context, appDiff.mPkgInfo);
if (appDiff.mInstalledAppInfo != null) {
AppSecurityPermissions perms = new AppSecurityPermissions(context, appDiff.pkgInfo);
if (appDiff.installedAppInfo != null) {
// update to an existing app
return perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW);
}

View File

@ -26,34 +26,33 @@ import org.fdroid.fdroid.data.Apk;
public class AppDiff {
private final PackageManager mPm;
public final PackageInfo mPkgInfo;
public ApplicationInfo mInstalledAppInfo;
private final PackageManager pm;
public final PackageInfo pkgInfo;
public ApplicationInfo installedAppInfo;
/**
* Constructor based on F-Droids Apk object
*/
public AppDiff(PackageManager mPm, Apk apk) {
this.mPm = mPm;
public AppDiff(PackageManager pm, Apk apk) {
this.pm = pm;
mPkgInfo = new PackageInfo();
mPkgInfo.packageName = apk.packageName;
mPkgInfo.applicationInfo = new ApplicationInfo();
mPkgInfo.requestedPermissions = apk.getFullPermissionsArray();
pkgInfo = new PackageInfo();
pkgInfo.packageName = apk.packageName;
pkgInfo.applicationInfo = new ApplicationInfo();
pkgInfo.requestedPermissions = apk.getFullPermissionsArray();
init();
}
private void init() {
String pkgName = mPkgInfo.packageName;
String pkgName = pkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
final String[] oldName = mPm.canonicalToCurrentPackageNames(new String[]{pkgName});
final String[] oldName = pm.canonicalToCurrentPackageNames(new String[]{pkgName});
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
pkgInfo.packageName = pkgName;
pkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed
try {
@ -61,13 +60,13 @@ public class AppDiff {
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
//noinspection WrongConstant (lint is actually wrong here!)
mInstalledAppInfo = mPm.getApplicationInfo(pkgName,
installedAppInfo = pm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mInstalledAppInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
mInstalledAppInfo = null;
if ((installedAppInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
installedAppInfo = null;
}
} catch (PackageManager.NameNotFoundException e) {
mInstalledAppInfo = null;
installedAppInfo = null;
}
}
}

View File

@ -78,22 +78,22 @@ public class AppSecurityPermissions {
public static final int WHICH_NEW = 1 << 2;
public static final int WHICH_ALL = 0xffff;
private final Context mContext;
private final LayoutInflater mInflater;
private final PackageManager mPm;
private final Map<String, MyPermissionGroupInfo> mPermGroups = new HashMap<>();
private final List<MyPermissionGroupInfo> mPermGroupsList = new ArrayList<>();
private final PermissionGroupInfoComparator mPermGroupComparator = new PermissionGroupInfoComparator();
private final PermissionInfoComparator mPermComparator = new PermissionInfoComparator();
private final CharSequence mNewPermPrefix;
private final Context context;
private final LayoutInflater inflater;
private final PackageManager pm;
private final Map<String, MyPermissionGroupInfo> permGroups = new HashMap<>();
private final List<MyPermissionGroupInfo> permGroupsList = new ArrayList<>();
private final PermissionGroupInfoComparator permGroupComparator = new PermissionGroupInfoComparator();
private final PermissionInfoComparator permComparator = new PermissionInfoComparator();
private final CharSequence newPermPrefix;
// PermissionGroupInfo implements Parcelable but its Parcel constructor is private and thus cannot be extended.
@SuppressLint("ParcelCreator")
static class MyPermissionGroupInfo extends PermissionGroupInfo {
CharSequence mLabel;
final List<MyPermissionInfo> mNewPermissions = new ArrayList<>();
final List<MyPermissionInfo> mAllPermissions = new ArrayList<>();
final List<MyPermissionInfo> newPermissions = new ArrayList<>();
final List<MyPermissionInfo> allPermissions = new ArrayList<>();
MyPermissionGroupInfo(PermissionInfo perm) {
name = perm.packageName;
@ -116,18 +116,18 @@ public class AppSecurityPermissions {
// PermissionInfo implements Parcelable but its Parcel constructor is private and thus cannot be extended.
@SuppressLint("ParcelCreator")
private static class MyPermissionInfo extends PermissionInfo {
CharSequence mLabel;
CharSequence label;
/**
* PackageInfo.requestedPermissionsFlags for the currently installed
* package, if it is installed.
*/
int mExistingReqFlags;
int existingReqFlags;
/**
* True if this should be considered a new permission.
*/
boolean mNew;
boolean newPerm;
MyPermissionInfo(PermissionInfo info) {
super(info);
@ -135,9 +135,9 @@ public class AppSecurityPermissions {
}
public static class PermissionItemView extends LinearLayout implements View.OnClickListener {
MyPermissionGroupInfo mGroup;
MyPermissionInfo mPerm;
AlertDialog mDialog;
MyPermissionGroupInfo group;
MyPermissionInfo perm;
AlertDialog dialog;
public PermissionItemView(Context context, AttributeSet attrs) {
super(context, attrs);
@ -146,8 +146,8 @@ public class AppSecurityPermissions {
public void setPermission(MyPermissionGroupInfo grp, MyPermissionInfo perm,
boolean first, CharSequence newPermPrefix) {
mGroup = grp;
mPerm = perm;
group = grp;
this.perm = perm;
ImageView permGrpIcon = (ImageView) findViewById(R.id.perm_icon);
TextView permNameView = (TextView) findViewById(R.id.perm_name);
@ -157,8 +157,8 @@ public class AppSecurityPermissions {
if (first) {
icon = grp.loadGroupIcon(getContext(), pm);
}
CharSequence label = perm.mLabel;
if (perm.mNew && newPermPrefix != null) {
CharSequence label = perm.label;
if (perm.newPerm && newPermPrefix != null) {
// If this is a new permission, format it appropriately.
SpannableStringBuilder builder = new SpannableStringBuilder();
Parcel parcel = Parcel.obtain();
@ -178,49 +178,49 @@ public class AppSecurityPermissions {
@Override
public void onClick(View v) {
if (mGroup != null && mPerm != null) {
if (mDialog != null) {
mDialog.dismiss();
if (group != null && perm != null) {
if (dialog != null) {
dialog.dismiss();
}
PackageManager pm = getContext().getPackageManager();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(mGroup.mLabel);
if (mPerm.descriptionRes != 0) {
builder.setMessage(mPerm.loadDescription(pm));
builder.setTitle(group.mLabel);
if (perm.descriptionRes != 0) {
builder.setMessage(perm.loadDescription(pm));
} else {
CharSequence appName;
try {
ApplicationInfo app = pm.getApplicationInfo(mPerm.packageName, 0);
ApplicationInfo app = pm.getApplicationInfo(perm.packageName, 0);
appName = app.loadLabel(pm);
} catch (NameNotFoundException e) {
appName = mPerm.packageName;
appName = perm.packageName;
}
builder.setMessage(getContext().getString(
R.string.perms_description_app, appName) + "\n\n" + mPerm.name);
R.string.perms_description_app, appName) + "\n\n" + perm.name);
}
builder.setCancelable(true);
builder.setIcon(mGroup.loadGroupIcon(getContext(), pm));
mDialog = builder.show();
mDialog.setCanceledOnTouchOutside(true);
builder.setIcon(group.loadGroupIcon(getContext(), pm));
dialog = builder.show();
dialog.setCanceledOnTouchOutside(true);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mDialog != null) {
mDialog.dismiss();
if (dialog != null) {
dialog.dismiss();
}
}
}
private AppSecurityPermissions(Context context) {
mContext = context;
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPm = mContext.getPackageManager();
this.context = context;
inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
pm = this.context.getPackageManager();
// Pick up from framework resources instead.
mNewPermPrefix = mContext.getText(R.string.perms_new_perm_prefix);
newPermPrefix = this.context.getText(R.string.perms_new_perm_prefix);
}
public AppSecurityPermissions(Context context, PackageInfo info) {
@ -233,7 +233,7 @@ public class AppSecurityPermissions {
PackageInfo installedPkgInfo = null;
if (info.requestedPermissions != null) {
try {
installedPkgInfo = mPm.getPackageInfo(info.packageName,
installedPkgInfo = pm.getPackageInfo(info.packageName,
PackageManager.GET_PERMISSIONS);
} catch (NameNotFoundException ignored) {
}
@ -259,7 +259,7 @@ public class AppSecurityPermissions {
for (String permName : strList) {
try {
PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0);
PermissionInfo tmpPermInfo = pm.getPermissionInfo(permName, 0);
if (tmpPermInfo == null) {
continue;
}
@ -288,11 +288,11 @@ public class AppSecurityPermissions {
groupName = tmpPermInfo.packageName;
tmpPermInfo.group = groupName;
}
MyPermissionGroupInfo group = mPermGroups.get(groupName);
MyPermissionGroupInfo group = permGroups.get(groupName);
if (group == null) {
PermissionGroupInfo grp = null;
if (origGroupName != null) {
grp = mPm.getPermissionGroupInfo(origGroupName, 0);
grp = pm.getPermissionGroupInfo(origGroupName, 0);
}
if (grp != null) {
group = new MyPermissionGroupInfo(grp);
@ -302,20 +302,20 @@ public class AppSecurityPermissions {
// gave couldn't be found. In either case, we consider
// its group to be the permission's package name.
tmpPermInfo.group = tmpPermInfo.packageName;
group = mPermGroups.get(tmpPermInfo.group);
group = permGroups.get(tmpPermInfo.group);
if (group == null) {
group = new MyPermissionGroupInfo(tmpPermInfo);
}
}
mPermGroups.put(tmpPermInfo.group, group);
permGroups.put(tmpPermInfo.group, group);
}
final boolean newPerm = installedPkgInfo != null
&& (existingFlags & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0;
MyPermissionInfo myPerm = new MyPermissionInfo(tmpPermInfo);
myPerm.mExistingReqFlags = existingFlags;
myPerm.existingReqFlags = existingFlags;
// This is a new permission if the app is already installed and
// doesn't currently hold this permission.
myPerm.mNew = newPerm;
myPerm.newPerm = newPerm;
permSet.add(myPerm);
} catch (NameNotFoundException e) {
Log.i(TAG, "Ignoring unknown permission:" + permName);
@ -326,26 +326,26 @@ public class AppSecurityPermissions {
private List<MyPermissionInfo> getPermissionList(MyPermissionGroupInfo grp, int which) {
switch (which) {
case WHICH_NEW:
return grp.mNewPermissions;
return grp.newPermissions;
default:
return grp.mAllPermissions;
return grp.allPermissions;
}
}
public int getPermissionCount(int which) {
int n = 0;
for (MyPermissionGroupInfo grp : mPermGroupsList) {
for (MyPermissionGroupInfo grp : permGroupsList) {
n += getPermissionList(grp, which).size();
}
return n;
}
public View getPermissionsView(int which) {
LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
LinearLayout permsView = (LinearLayout) inflater.inflate(R.layout.app_perms_summary, null);
LinearLayout displayList = (LinearLayout) permsView.findViewById(R.id.perms_list);
View noPermsView = permsView.findViewById(R.id.no_permissions);
displayPermissions(mPermGroupsList, displayList, which);
displayPermissions(permGroupsList, displayList, which);
if (displayList.getChildCount() <= 0) {
noPermsView.setVisibility(View.VISIBLE);
}
@ -361,21 +361,21 @@ public class AppSecurityPermissions {
LinearLayout permListView, int which) {
permListView.removeAllViews();
int spacing = (int) (8 * mContext.getResources().getDisplayMetrics().density);
int spacing = (int) (8 * context.getResources().getDisplayMetrics().density);
for (MyPermissionGroupInfo grp : groups) {
final List<MyPermissionInfo> perms = getPermissionList(grp, which);
for (int j = 0; j < perms.size(); j++) {
MyPermissionInfo perm = perms.get(j);
View view = getPermissionItemView(grp, perm, j == 0,
which != WHICH_NEW ? mNewPermPrefix : null);
which != WHICH_NEW ? newPermPrefix : null);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
if (j == 0) {
lp.topMargin = spacing;
}
if (j == grp.mAllPermissions.size() - 1) {
if (j == grp.allPermissions.size() - 1) {
lp.bottomMargin = spacing;
}
if (permListView.getChildCount() == 0) {
@ -388,7 +388,7 @@ public class AppSecurityPermissions {
private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp,
MyPermissionInfo perm, boolean first, CharSequence newPermPrefix) {
PermissionItemView permView = (PermissionItemView) mInflater.inflate(
PermissionItemView permView = (PermissionItemView) inflater.inflate(
Build.VERSION.SDK_INT >= 17 &&
(perm.flags & PermissionInfo.FLAG_COSTS_MONEY) != 0
? R.layout.app_permission_item_money : R.layout.app_permission_item,
@ -400,17 +400,11 @@ public class AppSecurityPermissions {
private boolean isDisplayablePermission(PermissionInfo pInfo, int existingReqFlags) {
final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
final boolean isNormal = base == PermissionInfo.PROTECTION_NORMAL;
// TODO: do we want this in F-Droid?
// We do not show normal permissions in the UI.
//if (isNormal) {
// return false;
//}
final boolean isDangerous = base == PermissionInfo.PROTECTION_DANGEROUS
|| ((pInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0);
// Dangerous and normal permissions are always shown to the user
// this is matches the permission list in AppDetails
if (isNormal || isDangerous) {
return true;
}
@ -441,16 +435,16 @@ public class AppSecurityPermissions {
}
public final int compare(MyPermissionInfo a, MyPermissionInfo b) {
return sCollator.compare(a.mLabel, b.mLabel);
return sCollator.compare(a.label, b.label);
}
}
private void addPermToList(List<MyPermissionInfo> permList,
MyPermissionInfo pInfo) {
if (pInfo.mLabel == null) {
pInfo.mLabel = pInfo.loadLabel(mPm);
if (pInfo.label == null) {
pInfo.label = pInfo.loadLabel(pm);
}
int idx = Collections.binarySearch(permList, pInfo, mPermComparator);
int idx = Collections.binarySearch(permList, pInfo, permComparator);
if (idx < 0) {
idx = -idx - 1;
permList.add(idx, pInfo);
@ -461,33 +455,33 @@ public class AppSecurityPermissions {
if (permList != null) {
// First pass to group permissions
for (MyPermissionInfo pInfo : permList) {
if (!isDisplayablePermission(pInfo, pInfo.mExistingReqFlags)) {
if (!isDisplayablePermission(pInfo, pInfo.existingReqFlags)) {
continue;
}
MyPermissionGroupInfo group = mPermGroups.get(pInfo.group);
MyPermissionGroupInfo group = permGroups.get(pInfo.group);
if (group != null) {
pInfo.mLabel = pInfo.loadLabel(mPm);
addPermToList(group.mAllPermissions, pInfo);
if (pInfo.mNew) {
addPermToList(group.mNewPermissions, pInfo);
pInfo.label = pInfo.loadLabel(pm);
addPermToList(group.allPermissions, pInfo);
if (pInfo.newPerm) {
addPermToList(group.newPermissions, pInfo);
}
}
}
}
for (MyPermissionGroupInfo pgrp : mPermGroups.values()) {
for (MyPermissionGroupInfo pgrp : permGroups.values()) {
if (pgrp.labelRes != 0 || pgrp.nonLocalizedLabel != null) {
pgrp.mLabel = pgrp.loadLabel(mPm);
pgrp.mLabel = pgrp.loadLabel(pm);
} else {
try {
ApplicationInfo app = mPm.getApplicationInfo(pgrp.packageName, 0);
pgrp.mLabel = app.loadLabel(mPm);
ApplicationInfo app = pm.getApplicationInfo(pgrp.packageName, 0);
pgrp.mLabel = app.loadLabel(pm);
} catch (NameNotFoundException e) {
pgrp.mLabel = pgrp.loadLabel(mPm);
pgrp.mLabel = pgrp.loadLabel(pm);
}
}
mPermGroupsList.add(pgrp);
permGroupsList.add(pgrp);
}
Collections.sort(mPermGroupsList, mPermGroupComparator);
Collections.sort(permGroupsList, permGroupComparator);
}
}

View File

@ -26,8 +26,8 @@ import android.widget.ScrollView;
* It's a ScrollView that knows how to stay awake.
*/
public class CaffeinatedScrollView extends ScrollView {
private Runnable mFullScrollAction;
private int mBottomSlop;
private Runnable fullScrollAction;
private int bottomSlop;
public CaffeinatedScrollView(Context context) {
super(context);
@ -47,8 +47,8 @@ public class CaffeinatedScrollView extends ScrollView {
}
public void setFullScrollAction(Runnable action) {
mFullScrollAction = action;
mBottomSlop = (int) (4 * getResources().getDisplayMetrics().density);
fullScrollAction = action;
bottomSlop = (int) (4 * getResources().getDisplayMetrics().density);
}
@Override
@ -64,12 +64,12 @@ public class CaffeinatedScrollView extends ScrollView {
}
private void checkFullScrollAction() {
if (mFullScrollAction != null) {
if (fullScrollAction != null) {
int daBottom = getChildAt(0).getBottom();
int screenBottom = getScrollY() + getHeight() - getPaddingBottom();
if ((daBottom - screenBottom) < mBottomSlop) {
mFullScrollAction.run();
mFullScrollAction = null;
if ((daBottom - screenBottom) < bottomSlop) {
fullScrollAction.run();
fullScrollAction = null;
}
}
}

View File

@ -72,7 +72,7 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
private static final String TAB_ID_ALL = "all";
private static final String TAB_ID_NEW = "new";
private App mApp;
private App app;
private final DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
@ -89,8 +89,8 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
ImageView appIcon = (ImageView) appSnippet.findViewById(R.id.app_icon);
TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost);
appName.setText(mApp.name);
ImageLoader.getInstance().displayImage(mApp.iconUrlLarge, appIcon,
appName.setText(app.name);
ImageLoader.getInstance().displayImage(app.iconUrlLarge, appIcon,
displayImageOptions);
tabHost.setup();
@ -106,9 +106,9 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
scrollView = null;
okCanInstall = false;
int msg = 0;
AppSecurityPermissions perms = new AppSecurityPermissions(this, appDiff.mPkgInfo);
if (appDiff.mInstalledAppInfo != null) {
msg = (appDiff.mInstalledAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
AppSecurityPermissions perms = new AppSecurityPermissions(this, appDiff.pkgInfo);
if (appDiff.installedAppInfo != null) {
msg = (appDiff.installedAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_update_system
: R.string.install_confirm_update;
scrollView = new CaffeinatedScrollView(this);
@ -144,10 +144,10 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
}
if (!permVisible) {
if (appDiff.mInstalledAppInfo != null) {
if (appDiff.installedAppInfo != null) {
// This is an update to an application, but there are no
// permissions at all.
msg = (appDiff.mInstalledAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
msg = (appDiff.installedAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_update_system_no_perms
: R.string.install_confirm_update_no_perms;
} else {
@ -192,18 +192,17 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
intent = getIntent();
Uri uri = intent.getData();
Apk apk = ApkProvider.Helper.find(this, uri, ApkProvider.DataColumns.ALL);
mApp = AppProvider.Helper.findByPackageName(getContentResolver(), apk.packageName);
app = AppProvider.Helper.findByPackageName(getContentResolver(), apk.packageName);
appDiff = new AppDiff(getPackageManager(), apk);
if (appDiff.mPkgInfo == null) {
if (appDiff.pkgInfo == null) {
setResult(RESULT_CANNOT_PARSE, intent);
finish();
}
setContentView(R.layout.install_start);
// increase dialog to full width for now
// TODO: create a better design and minimum width for tablets
// increase dialog to full width
getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);

View File

@ -43,23 +43,23 @@ import java.util.List;
*/
class TabsAdapter extends PagerAdapter
implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final TabHost mTabHost;
private final ViewPager mViewPager;
private final List<View> mTabs = new ArrayList<>();
private final Rect mTempRect = new Rect();
private TabHost.OnTabChangeListener mOnTabChangeListener;
private final Context context;
private final TabHost tabHost;
private final ViewPager viewPager;
private final List<View> tabs = new ArrayList<>();
private final Rect tempRect = new Rect();
private TabHost.OnTabChangeListener onTabChangeListener;
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
private final Context context;
DummyTabFactory(Context context) {
mContext = context;
this.context = context;
}
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
View v = new View(context);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
@ -67,29 +67,29 @@ class TabsAdapter extends PagerAdapter
}
TabsAdapter(Activity activity, TabHost tabHost, ViewPager pager) {
mContext = activity;
mTabHost = tabHost;
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
context = activity;
this.tabHost = tabHost;
viewPager = pager;
this.tabHost.setOnTabChangedListener(this);
viewPager.setAdapter(this);
viewPager.setOnPageChangeListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, View view) {
tabSpec.setContent(new DummyTabFactory(mContext));
mTabs.add(view);
mTabHost.addTab(tabSpec);
tabSpec.setContent(new DummyTabFactory(context));
tabs.add(view);
tabHost.addTab(tabSpec);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
return tabs.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = mTabs.get(position);
View view = tabs.get(position);
container.addView(view);
return view;
}
@ -105,15 +105,15 @@ class TabsAdapter extends PagerAdapter
}
public void setOnTabChangedListener(TabHost.OnTabChangeListener listener) {
mOnTabChangeListener = listener;
onTabChangeListener = listener;
}
@Override
public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
if (mOnTabChangeListener != null) {
mOnTabChangeListener.onTabChanged(tabId);
int position = tabHost.getCurrentTab();
viewPager.setCurrentItem(position);
if (onTabChangeListener != null) {
onTabChangeListener.onTabChanged(tabId);
}
}
@ -128,19 +128,19 @@ class TabsAdapter extends PagerAdapter
// The jerk.
// This hack tries to prevent this from pulling focus out of our
// ViewPager.
TabWidget widget = mTabHost.getTabWidget();
TabWidget widget = tabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
tabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
// Scroll the current tab into visibility if needed.
View tab = widget.getChildTabViewAt(position);
mTempRect.set(tab.getLeft(), tab.getTop(), tab.getRight(), tab.getBottom());
widget.requestRectangleOnScreen(mTempRect, false);
tempRect.set(tab.getLeft(), tab.getTop(), tab.getRight(), tab.getBottom());
widget.requestRectangleOnScreen(tempRect, false);
// Make sure the scrollbars are visible for a moment after selection
final View contentView = mTabs.get(position);
final View contentView = tabs.get(position);
if (contentView instanceof CaffeinatedScrollView) {
((CaffeinatedScrollView) contentView).awakenScrollBars();
}

View File

@ -225,28 +225,17 @@ Changelog" />
android:drawableRight="@drawable/ic_expand_more_grey600"
android:drawableEnd="@drawable/ic_expand_more_grey600" />
<TextView
android:id="@+id/permissions_list"
<LinearLayout
android:id="@+id/permission_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="false"
android:orientation="vertical"
android:fontFamily="sans-serif-light"
android:textSize="14sp"
android:visibility="gone"
android:layout_marginLeft="@dimen/layout_horizontal_margin"
android:layout_marginStart="@dimen/layout_horizontal_margin"
tools:text=" * Full network access
* View network connections
* View Wi-Fi connections
* Connect and disconnect from Wi-Fi
* Pair with Bluetooth devices
* Run at startup
* Modify or delete the contents of your USB storage
* Control Near Field Communication
* Directly install apps
* Delete apps
* Full permission to all device features and storage
* Test access to protected storage" />
android:paddingEnd="4dp"
android:paddingRight="4dp"
tools:ignore="RtlSymmetry" />
</LinearLayout>