Permalink
Browse files

Frameworks: Privacy Guard part 2 (1/2)

Current implementation does not really merge both awesome features
appops and privacy guard. As well it is from UX perspective too complicated

So this commits changes:

- Move int array to logical correct place AppOpsManager
- Switch only the privacy guard permissions which the app
  really requests and not all...this irritates the user
- give support for custom permission set and reflect this state
  with an icon in notification and pgm
- add pack filterpermission feature due that user mainly are interested
  in the apps which use critical personal data
- permit by default as well writing off personal data
- do not show apps where either permissions are not changeable due
  off appops or apps which do not have permissions at all
- ability to hide pg notification
- remove pg checkbox in InstalledAppdetails and add a button to
  modify appops. Button is disabled if either the app does not have
  permissions or appops does not support it. As well for platform
  certificate apps
- add on appops detail screen reset and privacy guard button to quick
  change all states
- rework of the complete dialog handling in pgm and add several dialogs
- move all notify icon for pgm and notification to frameworks base
- and a lot more minor fixes and fc fixes

cheers

PatchSet:
- correct privacy guard filter logic
- add pgm map
- add status icons.....PGM shows either off/partly enabled/enabled
  in addition to it other set permissions shows a red plus sign on
  the top right corner of the PGM icon on all states
- tapping on PGM and menu pgm button on detail appops screen turns on/off
  only PGM permissions to be more consistent
- some minor fixes

Change-Id: I990a6c7f25cdee5febdb95c1e26c022d6bcb27e0
  • Loading branch information...
kufikugel authored and Gerrit Code Review committed Oct 10, 2013
1 parent 854ade6 commit 97ccae06cd0ad1aa366c3a70e8e744277c409b06
Showing with 259 additions and 41 deletions.
  1. +90 −8 core/java/android/app/AppOpsManager.java
  2. +21 −1 core/java/android/provider/Settings.java
  3. +4 −3 core/java/com/android/internal/app/IAppOpsService.aidl
  4. BIN core/res/res/drawable-hdpi/stat_notify_privacy_guard_custom.png
  5. BIN core/res/res/drawable-hdpi/stat_notify_privacy_guard_custom_plus.png
  6. BIN core/res/res/drawable-hdpi/stat_notify_privacy_guard_off.png
  7. BIN core/res/res/drawable-hdpi/stat_notify_privacy_guard_off_plus.png
  8. BIN core/res/res/drawable-hdpi/stat_notify_privacy_guard_plus.png
  9. BIN core/res/res/drawable-mdpi/stat_notify_privacy_guard_custom.png
  10. BIN core/res/res/drawable-mdpi/stat_notify_privacy_guard_custom_plus.png
  11. BIN core/res/res/drawable-mdpi/stat_notify_privacy_guard_off.png
  12. BIN core/res/res/drawable-mdpi/stat_notify_privacy_guard_off_plus.png
  13. BIN core/res/res/drawable-mdpi/stat_notify_privacy_guard_plus.png
  14. BIN core/res/res/drawable-xhdpi/stat_notify_privacy_guard_custom.png
  15. BIN core/res/res/drawable-xhdpi/stat_notify_privacy_guard_custom_plus.png
  16. BIN core/res/res/drawable-xhdpi/stat_notify_privacy_guard_off.png
  17. BIN core/res/res/drawable-xhdpi/stat_notify_privacy_guard_off_plus.png
  18. BIN core/res/res/drawable-xhdpi/stat_notify_privacy_guard_plus.png
  19. BIN core/res/res/drawable-xxhdpi/stat_notify_privacy_guard_custom.png
  20. BIN core/res/res/drawable-xxhdpi/stat_notify_privacy_guard_custom_plus.png
  21. BIN core/res/res/drawable-xxhdpi/stat_notify_privacy_guard_off.png
  22. BIN core/res/res/drawable-xxhdpi/stat_notify_privacy_guard_off_plus.png
  23. BIN core/res/res/drawable-xxhdpi/stat_notify_privacy_guard_plus.png
  24. +1 −0 core/res/res/values/slim_strings.xml
  25. +6 −0 core/res/res/values/slim_symbols.xml
  26. +119 −20 services/java/com/android/server/AppOpsService.java
  27. +8 −3 services/java/com/android/server/am/ActivityManagerService.java
  28. +9 −5 services/java/com/android/server/am/ActivityStack.java
  29. +1 −1 services/java/com/android/server/pm/PackageManagerService.java
@@ -62,7 +62,7 @@

// when adding one of these:
// - increment _NUM_OP
// - add rows to sOpToSwitch, sOpNames, sOpPerms
// - add rows to sOpToSwitch, sOpNames, sOpPerms, sPrivacyGuardOp
// - add descriptive strings to Settings/res/values/arrays.xml
public static final int OP_NONE = -1;
public static final int OP_COARSE_LOCATION = 0;
@@ -104,7 +104,7 @@
* switch to determine whether it is allowed. Generally this is
* a 1:1 mapping, but for some things (like location) that have
* multiple low-level operations being tracked that should be
* presented to hte user as one switch then this can be used to
* presented to the user as one switch then this can be used to
* make them all controlled by the same single operation.
*/
private static int[] sOpToSwitch = new int[] {
@@ -217,6 +217,54 @@
null, // no permission for writing clipboard
};

/**
* Privacy Guard Ops and states need to
* match general Ops map. Unused Ops are flagged as OP_NONE
*/
private static final int[] sPrivacyGuardOp = new int[] {
OP_COARSE_LOCATION,
OP_COARSE_LOCATION,
OP_COARSE_LOCATION,
OP_NONE,
OP_READ_CONTACTS,
OP_WRITE_CONTACTS,
OP_READ_CALL_LOG,
OP_WRITE_CALL_LOG,
OP_READ_CALENDAR,
OP_WRITE_CALENDAR,
OP_COARSE_LOCATION,
OP_NONE,
OP_COARSE_LOCATION,
OP_NONE,
OP_READ_SMS,
OP_WRITE_SMS,
OP_READ_SMS,
OP_READ_SMS,
OP_READ_SMS,
OP_READ_SMS,
OP_WRITE_SMS,
OP_READ_SMS,
OP_WRITE_SMS,
OP_NONE,
OP_NONE,
OP_NONE,
OP_NONE,
OP_NONE,
OP_NONE,
OP_NONE,
OP_NONE,
};

/**
* Privacy Guard states
*/
public static final int PRIVACY_GUARD_DISABLED = 0;
public static final int PRIVACY_GUARD_DISABLED_PLUS = 1;
public static final int PRIVACY_GUARD_ENABLED = 2;
public static final int PRIVACY_GUARD_ENABLED_PLUS = 3;
public static final int PRIVACY_GUARD_CUSTOM = 4;
public static final int PRIVACY_GUARD_CUSTOM_PLUS = 5;

/**
* Retrieve the op switch that controls the given operation.
*/
@@ -239,6 +287,19 @@ public static String opToPermission(int op) {
return sOpPerms[op];
}

/**
* Retrieve the permission associated privacy guard operation,
* or OP_NONE if there is not one.
*/
public static int getPrivacyGuardOp(String permission) {
for (int i=0; i<sOpPerms.length; i++) {
if (sOpPerms[i] != null && sOpPerms[i].equals(permission)) {
return sPrivacyGuardOp[i];
}
}
return OP_NONE;
}

/**
* Class holding all of the operation information associated with an app.
*/
@@ -540,27 +601,48 @@ public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getBasePackageName());
}

public List<AppOpsManager.PackageOps> getPrivacyGuardOpsForPackage(int uid, String packageName) {
public List<Integer> getPrivacyGuardOpsForPackage(String packageName) {
try {
return mService.getPrivacyGuardOpsForPackage(uid, packageName);
return mService.getPrivacyGuardOpsForPackage(packageName);
} catch (RemoteException e) {
}
return null;
}

public boolean getPrivacyGuardSettingForPackage(int uid, String packageName) {
public int getPrivacyGuardSettingForPackage(int uid, String packageName) {
try {
return mService.getPrivacyGuardSettingForPackage(uid, packageName);
} catch (RemoteException e) {
}
return false;
return PRIVACY_GUARD_DISABLED;
}

public void setPrivacyGuardSettingForPackage(int uid, String packageName,
boolean state) {
boolean state, boolean forceAll) {
try {
mService.setPrivacyGuardSettingForPackage(uid, packageName, state);
mService.setPrivacyGuardSettingForPackage(uid, packageName, state, forceAll);
} catch (RemoteException e) {
}
}

/**
* Retrieve the privacy guard state associated icons for notification and settings
*/
public static int getPrivacyGuardIconResId(int pgState) {
switch (pgState) {
case PRIVACY_GUARD_DISABLED:
return com.android.internal.R.drawable.stat_notify_privacy_guard_off;
case PRIVACY_GUARD_ENABLED:
return com.android.internal.R.drawable.stat_notify_privacy_guard;
case PRIVACY_GUARD_CUSTOM:
return com.android.internal.R.drawable.stat_notify_privacy_guard_custom;
case PRIVACY_GUARD_DISABLED_PLUS:
return com.android.internal.R.drawable.stat_notify_privacy_guard_off_plus;
case PRIVACY_GUARD_ENABLED_PLUS:
return com.android.internal.R.drawable.stat_notify_privacy_guard_plus;
case PRIVACY_GUARD_CUSTOM_PLUS:
return com.android.internal.R.drawable.stat_notify_privacy_guard_custom_plus;
}
return com.android.internal.R.drawable.stat_notify_privacy_guard_off;
}
}
@@ -470,6 +470,19 @@
public static final String ACTION_APPLICATION_DETAILS_SETTINGS =
"android.settings.APPLICATION_DETAILS_SETTINGS";

/**
* @hide
* Activity Action: Show the "app ops" details screen.
* <p>
* Input: The Intent's data URI specifies the application package name
* to be shown, with the "package" scheme. That is "package:com.my.app".
* <p>
* Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APP_OPS_DETAILS_SETTINGS =
"android.settings.APP_OPS_DETAILS_SETTINGS";

/**
* @hide
* Activity Action: Show the "app ops" settings screen.
@@ -6043,6 +6056,12 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val
*/
public static final String PRIVACY_GUARD_DEFAULT = "privacy_guard_default";

/**
* Whether privacy guard notification should show.
* @hide
*/
public static final String PRIVACY_GUARD_NOTIFICATION = "privacy_guard_notification";

/**
* Name of a package that the current user has explicitly allowed to see all of that
* user's notifications.
@@ -6106,7 +6125,8 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val
LOCK_SCREEN_OWNER_INFO_ENABLED,
ADVANCED_REBOOT,
DIALPAD_AUTOCOMPLETE,
PRIVACY_GUARD_DEFAULT
PRIVACY_GUARD_DEFAULT,
PRIVACY_GUARD_NOTIFICATION
};

/**
@@ -36,7 +36,8 @@ interface IAppOpsService {
void resetAllModes();

// Privacy guard methods
List<AppOpsManager.PackageOps> getPrivacyGuardOpsForPackage(int uid, String packageName);
boolean getPrivacyGuardSettingForPackage(int uid, String packageName);
void setPrivacyGuardSettingForPackage(int uid, String packageName, boolean state);
List getPrivacyGuardOpsForPackage(String packageName);
int getPrivacyGuardSettingForPackage(int uid, String packageName);
void setPrivacyGuardSettingForPackage(int uid, String packageName,
boolean state, boolean forceAll);
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -150,5 +150,6 @@
<string name="permdesc_changePrivacyGuardState">Allows the app to change whether another app runs with Privacy Guard. When an app is running with Privacy Guard, it will not have access to personal data such as contacts, call logs, or messages.</string>
<string name="privacy_guard_notification">Privacy Guard active</string>
<string name="privacy_guard_notification_detail"><xliff:g id="app">%1$s</xliff:g> will not be able to access personal data</string>
<string name="privacy_guard_custom_notification_detail"><xliff:g id="app">%1$s</xliff:g> will not be able to access custom permissions</string>

</resources>
@@ -107,7 +107,13 @@
<!-- Privacy Guard -->
<java-symbol type="string" name="privacy_guard_notification" />
<java-symbol type="string" name="privacy_guard_notification_detail" />
<java-symbol type="string" name="privacy_guard_custom_notification_detail" />
<java-symbol type="drawable" name="stat_notify_privacy_guard" />
<java-symbol type="drawable" name="stat_notify_privacy_guard_off" />
<java-symbol type="drawable" name="stat_notify_privacy_guard_custom" />
<java-symbol type="drawable" name="stat_notify_privacy_guard_plus" />
<java-symbol type="drawable" name="stat_notify_privacy_guard_off_plus" />
<java-symbol type="drawable" name="stat_notify_privacy_guard_custom_plus" />

<!-- Irda Service -->
<java-symbol type="bool" name="config_enableIrdaManagerService" />
@@ -31,6 +31,7 @@

import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.AsyncTask;
@@ -69,14 +70,6 @@
final AtomicFile mFile;
final Handler mHandler;

private static final int[] PRIVACY_GUARD_OP_STATES = new int[] {
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_READ_CALL_LOG,
AppOpsManager.OP_READ_CONTACTS,
AppOpsManager.OP_READ_CALENDAR,
AppOpsManager.OP_READ_SMS
};

boolean mWriteScheduled;
final Runnable mWriteRunner = new Runnable() {
public void run() {
@@ -939,26 +932,132 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
}

@Override
public List<AppOpsManager.PackageOps> getPrivacyGuardOpsForPackage(int uid, String packageName) {
return getOpsForPackage(uid, packageName, PRIVACY_GUARD_OP_STATES);
public List<Integer> getPrivacyGuardOpsForPackage(String packageName) {
PackageInfo pkgInfo;
List<Integer> ops = new ArrayList<Integer>();
try {
pkgInfo = mContext.getPackageManager()
.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
} catch (NameNotFoundException e) {
return ops;
}
// we need to get all relevant permissions of the package.
// Only calling getOpsForPackage does not return ops
// with AppOpsManager.MODE_ALLOWED which never got
// granted and do not show up in Ops statistics
final String[] requestedPermissions = pkgInfo.requestedPermissions;
if (requestedPermissions != null) {
for (String requested : requestedPermissions) {
int curOp = AppOpsManager.getPrivacyGuardOp(requested);
boolean duplicate = false;
// check for duplicates
for (int op : ops) {
if (op == curOp) {
duplicate = true;
}
}
if (curOp != AppOpsManager.OP_NONE && !duplicate) {
ops.add(curOp);
}
}
}
return ops;
}

@Override
public boolean getPrivacyGuardSettingForPackage(int uid, String packageName) {
for (int op : PRIVACY_GUARD_OP_STATES) {
if (checkOperation(op, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
return true;
public int getPrivacyGuardSettingForPackage(int uid, String packageName) {
int privacyGuardState;
boolean pgDetect;
boolean isCustomOpPresent = false;

List<AppOpsManager.PackageOps> packageOps =
getOpsForPackage(uid, packageName, null);
List<Integer> privacyGuardOps = getPrivacyGuardOpsForPackage(packageName);
List<Integer> privacyGuardOpsHelper = new ArrayList<Integer>(privacyGuardOps);

// get disabled Ops and check for custom Op changes
if (packageOps != null) {
for (AppOpsManager.OpEntry op : packageOps.get(0).getOps()) {
pgDetect = false;
if (checkOperation(op.getOp(), uid, packageName)
== AppOpsManager.MODE_IGNORED) {
for (int pgOp : privacyGuardOps) {
if (AppOpsManager.opToSwitch(op.getOp()) == pgOp) {
privacyGuardOpsHelper.remove((Integer) pgOp);
pgDetect = true;
break;
}
}
if (!pgDetect) {
isCustomOpPresent = true;
}
}
}
}

// get privacy guard state
if (!privacyGuardOps.isEmpty()
&& privacyGuardOps.size() != privacyGuardOpsHelper.size()) {
if (privacyGuardOpsHelper.isEmpty()) {
privacyGuardState = AppOpsManager.PRIVACY_GUARD_ENABLED;
} else {
privacyGuardState = AppOpsManager.PRIVACY_GUARD_CUSTOM;
}
} else {
privacyGuardState = AppOpsManager.PRIVACY_GUARD_DISABLED;
}
return false;

// return current mode
switch (privacyGuardState) {
case AppOpsManager.PRIVACY_GUARD_ENABLED:
if (isCustomOpPresent) {
return AppOpsManager.PRIVACY_GUARD_ENABLED_PLUS;
} else {
return AppOpsManager.PRIVACY_GUARD_ENABLED;
}
case AppOpsManager.PRIVACY_GUARD_CUSTOM:
if (isCustomOpPresent) {
return AppOpsManager.PRIVACY_GUARD_CUSTOM_PLUS;
} else {
return AppOpsManager.PRIVACY_GUARD_CUSTOM;
}
case AppOpsManager.PRIVACY_GUARD_DISABLED:
if (isCustomOpPresent) {
return AppOpsManager.PRIVACY_GUARD_DISABLED_PLUS;
} else {
return AppOpsManager.PRIVACY_GUARD_DISABLED;
}
}
return AppOpsManager.PRIVACY_GUARD_DISABLED;
}

@Override
public void setPrivacyGuardSettingForPackage(int uid, String packageName, boolean state) {
for (int op : PRIVACY_GUARD_OP_STATES) {
int switchOp = AppOpsManager.opToSwitch(op);
setMode(switchOp, uid, packageName, state
public void setPrivacyGuardSettingForPackage(int uid, String packageName,
boolean state, boolean forceAll) {
List<Integer> switchOps;
if (!forceAll) {
// retrieve specific privacy guard permissions
switchOps = getPrivacyGuardOpsForPackage(packageName);
} else {
// if user want to enable all permissions on the package
// we need to retrieve the disabled ops.
// All ops are retrieved via getOpsForPackage
// which are flagged with AppOpsManager.MODE_IGNORED
switchOps = new ArrayList<Integer>();
List<AppOpsManager.PackageOps> packageOps =
getOpsForPackage(uid, packageName, null);
if (packageOps != null) {
for (AppOpsManager.OpEntry op : packageOps.get(0).getOps()) {
if (checkOperation(op.getOp(), uid, packageName)
== AppOpsManager.MODE_IGNORED) {
switchOps.add(AppOpsManager.opToSwitch(op.getOp()));
}
}
}
}

for (int op : switchOps) {
setMode(op, uid, packageName, state
? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED);
}
}
Oops, something went wrong.

0 comments on commit 97ccae0

Please sign in to comment.