android6.0系统允许用户管理应用权限,可以关闭/打开权限。
所以需要在APP中增加权限判断,以免用户关闭相应权限后,APP运行异常。
以MMS为例,在系统设置——应用——MMS——权限——>关闭短信权限
这个界面的处理代码在 android\packages\apps\PackageInstaller 中。
通过调试 PackageInstaller,可以知道短信权限对应是 permissionGroup: android.permission-group.SMS
其中包含的具体permission:
android.permission.READ_SMS,
android.permission.RECEIVE_WAP_PUSH,
android.permission.RECEIVE_MMS,
android.permission.RECEIVE_SMS,
android.permission.SEND_SMS,
android.permission.READ_CELL_BROADCASTS
关闭短信权限后,MMS无法读取,收发信息。操作MMS还会出现报错现象。所以需要在MMS启动时增加权限判断。
查看PackageInstaller中关闭权限的处理
AppOpsManager mAppOps = context.getSystemService(AppOpsManager.class);
......
// Disable the app op. mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_IGNORED); //将权限对应的操作标记为 AppOpsManager.MODE_IGNORED,使权限被限制
AppOpsManager 是专门管理 APP操作权限的, 所以用AppOpsManager来判断权限是否被允许。
AppOpsManager中定义了系统权限对应的int码,和string字符。可以直接拿来用
android\frameworks\base\core\java\android\app\AppOpsManager.java
/** @hide No operation specified. */ public static final int OP_NONE = -1; /** @hide Access to coarse location information. */ public static final int OP_COARSE_LOCATION = 0; /** @hide Access to fine location information. */ public static final int OP_FINE_LOCATION = 1; /** @hide Causing GPS to run. */ public static final int OP_GPS = 2; /** @hide */ public static final int OP_VIBRATE = 3; /** @hide */ public static final int OP_READ_CONTACTS = 4; /** @hide */ public static final int OP_WRITE_CONTACTS = 5; /** @hide */ public static final int OP_READ_CALL_LOG = 6; /** @hide */ public static final int OP_WRITE_CALL_LOG = 7; /** @hide */ public static final int OP_READ_CALENDAR = 8; /** @hide */ public static final int OP_WRITE_CALENDAR = 9; /** @hide */ public static final int OP_WIFI_SCAN = 10; /** @hide */ public static final int OP_POST_NOTIFICATION = 11; /** @hide */ public static final int OP_NEIGHBORING_CELLS = 12; /** @hide */ public static final int OP_CALL_PHONE = 13; /** @hide */ public static final int OP_READ_SMS = 14; /** @hide */ public static final int OP_WRITE_SMS = 15; /** @hide */ public static final int OP_RECEIVE_SMS = 16; /** @hide */ public static final int OP_RECEIVE_EMERGECY_SMS = 17; /** @hide */ public static final int OP_RECEIVE_MMS = 18; /** @hide */ public static final int OP_RECEIVE_WAP_PUSH = 19; /** @hide */ public static final int OP_SEND_SMS = 20; /** @hide */ public static final int OP_READ_ICC_SMS = 21; /** @hide */ public static final int OP_WRITE_ICC_SMS = 22; /** @hide */ public static final int OP_WRITE_SETTINGS = 23; /** @hide */ public static final int OP_SYSTEM_ALERT_WINDOW = 24; /** @hide */ public static final int OP_ACCESS_NOTIFICATIONS = 25; /** @hide */ public static final int OP_CAMERA = 26; /** @hide */ public static final int OP_RECORD_AUDIO = 27; /** @hide */ public static final int OP_PLAY_AUDIO = 28; /** @hide */ public static final int OP_READ_CLIPBOARD = 29; /** @hide */ public static final int OP_WRITE_CLIPBOARD = 30; /** @hide */ public static final int OP_TAKE_MEDIA_BUTTONS = 31; /** @hide */ public static final int OP_TAKE_AUDIO_FOCUS = 32; /** @hide */ public static final int OP_AUDIO_MASTER_VOLUME = 33; /** @hide */ public static final int OP_AUDIO_VOICE_VOLUME = 34; /** @hide */ public static final int OP_AUDIO_RING_VOLUME = 35; /** @hide */ public static final int OP_AUDIO_MEDIA_VOLUME = 36; /** @hide */ public static final int OP_AUDIO_ALARM_VOLUME = 37; /** @hide */ public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38; /** @hide */ public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39; /** @hide */ public static final int OP_WAKE_LOCK = 40; /** @hide Continually monitoring location data. */ public static final int OP_MONITOR_LOCATION = 41; /** @hide Continually monitoring location data with a relatively high power request. */ public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */ public static final int OP_GET_USAGE_STATS = 43; /** @hide */ public static final int OP_MUTE_MICROPHONE = 44; /** @hide */ public static final int OP_TOAST_WINDOW = 45; /** @hide Capture the device's display contents and/or audio */ public static final int OP_PROJECT_MEDIA = 46; /** @hide Activate a VPN connection without user intervention. */ public static final int OP_ACTIVATE_VPN = 47; /** @hide Access the WallpaperManagerAPI to write wallpapers. */ public static final int OP_WRITE_WALLPAPER = 48; /** @hide Received the assist structure from an app. */ public static final int OP_ASSIST_STRUCTURE = 49; /** @hide Received a screenshot from assist. */ public static final int OP_ASSIST_SCREENSHOT = 50; /** @hide Read the phone state. */ public static final int OP_READ_PHONE_STATE = 51; /** @hide Add voicemail messages to the voicemail content provider. */ public static final int OP_ADD_VOICEMAIL = 52; /** @hide Access APIs for SIP calling over VOIP or WiFi. */ public static final int OP_USE_SIP = 53; /** @hide Intercept outgoing calls. */ public static final int OP_PROCESS_OUTGOING_CALLS = 54; /** @hide User the fingerprint API. */ public static final int OP_USE_FINGERPRINT = 55; /** @hide Access to body sensors such as heart rate, etc. */ public static final int OP_BODY_SENSORS = 56; /** @hide Read previously received cell broadcast messages. */ public static final int OP_READ_CELL_BROADCASTS = 57; /** @hide Inject mock location into the system. */ public static final int OP_MOCK_LOCATION = 58; /** @hide Read external storage. */ public static final int OP_READ_EXTERNAL_STORAGE = 59; /** @hide Write external storage. */ public static final int OP_WRITE_EXTERNAL_STORAGE = 60; /** @hide Turned on the screen. */ public static final int OP_TURN_SCREEN_ON = 61; /** @hide Get device accounts. */ public static final int OP_GET_ACCOUNTS = 62; /** @hide */ public static final int _NUM_OP = 63;
//--------------------------------上面的int 类型标记了@hide,需要在源码下才能调用编译通过。对于普通APP,可以用下面的string 类型-----------------------------//
/** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; /** Access to fine location information. */ public static final String OPSTR_FINE_LOCATION = "android:fine_location"; /** Continually monitoring location data. */ public static final String OPSTR_MONITOR_LOCATION = "android:monitor_location"; /** Continually monitoring location data with a relatively high power request. */ public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power"; /** Access to {@link android.app.usage.UsageStatsManager}. */ public static final String OPSTR_GET_USAGE_STATS = "android:get_usage_stats"; /** Activate a VPN connection without user intervention. @hide */ @SystemApi public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; /** Allows an application to read the user's contacts data. */ public static final String OPSTR_READ_CONTACTS = "android:read_contacts"; /** Allows an application to write to the user's contacts data. */ public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts"; /** Allows an application to read the user's call log. */ public static final String OPSTR_READ_CALL_LOG = "android:read_call_log"; /** Allows an application to write to the user's call log. */ public static final String OPSTR_WRITE_CALL_LOG = "android:write_call_log"; /** Allows an application to read the user's calendar data. */ public static final String OPSTR_READ_CALENDAR = "android:read_calendar"; /** Allows an application to write to the user's calendar data. */ public static final String OPSTR_WRITE_CALENDAR = "android:write_calendar"; /** Allows an application to initiate a phone call. */ public static final String OPSTR_CALL_PHONE = "android:call_phone"; /** Allows an application to read SMS messages. */ public static final String OPSTR_READ_SMS = "android:read_sms"; /** Allows an application to receive SMS messages. */ public static final String OPSTR_RECEIVE_SMS = "android:receive_sms"; /** Allows an application to receive MMS messages. */ public static final String OPSTR_RECEIVE_MMS = "android:receive_mms"; /** Allows an application to receive WAP push messages. */ public static final String OPSTR_RECEIVE_WAP_PUSH = "android:receive_wap_push"; /** Allows an application to send SMS messages. */ public static final String OPSTR_SEND_SMS = "android:send_sms"; /** Required to be able to access the camera device. */ public static final String OPSTR_CAMERA = "android:camera"; /** Required to be able to access the microphone device. */ public static final String OPSTR_RECORD_AUDIO = "android:record_audio"; /** Required to access phone state related information. */ public static final String OPSTR_READ_PHONE_STATE = "android:read_phone_state"; /** Required to access phone state related information. */ public static final String OPSTR_ADD_VOICEMAIL = "android:add_voicemail"; /** Access APIs for SIP calling over VOIP or WiFi */ public static final String OPSTR_USE_SIP = "android:use_sip"; /** Use the fingerprint API. */ public static final String OPSTR_USE_FINGERPRINT = "android:use_fingerprint"; /** Access to body sensors such as heart rate, etc. */ public static final String OPSTR_BODY_SENSORS = "android:body_sensors"; /** Read previously received cell broadcast messages. */ public static final String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts"; /** Inject mock location into the system. */ public static final String OPSTR_MOCK_LOCATION = "android:mock_location"; /** Read external storage. */ public static final String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage"; /** Write external storage. */ public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage"; /** Required to draw on top of other apps. */ public static final String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window"; /** Required to write/modify/update system settingss. */ public static final String OPSTR_WRITE_SETTINGS = "android:write_settings"; /** @hide Get device accounts. */ public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
检查权限方法
public int checkOp(String op, int uid, String packageName) { return checkOp(strOpToOp(op), uid, packageName); //strOpToOp(op)将string码转为int码,相当于调用checkOp(int op, int uid, String packageName)
//checkOp(int op, int uid, String packageName)是@hide的,所以只有源码环境下才能直接调用,编译。
}
下面是我写的MMS中检查权限的方法。
public static void mmsPermissionCheck(Context context){ final String smsPermissionGroupName = "android.permission-group.SMS"; final Handler handler = new Handler(); final Context mContext = context; final Runnable showPermissonCheck = new Runnable() { public void run() { new AlertDialog.Builder(mContext) .setMessage(mContext.getString(R.string.check_mms_permission)) .setPositiveButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { ((Activity)mContext).finish(); } }) .setCancelable(false) .create().show(); } }; PackageManager pm = context.getPackageManager(); AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); //AppOpsManager 用来判断权限 try { PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(),PackageManager.GET_PERMISSIONS); for(PermissionGroupInfo permissionGroupInfo : pm.getAllPermissionGroups(0) ){ Log.i("antoon", permissionGroupInfo.name); } /** * permissionGroup: android.permission-group.SMS * permission: android.permission.READ_SMS, android.permission.RECEIVE_WAP_PUSH, * android.permission.RECEIVE_MMS, android.permission.RECEIVE_SMS, * android.permission.SEND_SMS, android.permission.READ_CELL_BROADCASTS * if permission denied, appOpsManager.checkOp(...) will return >=1 */ int resultCount = 0; for(PermissionInfo permissionInfo : pm.queryPermissionsByGroup(smsPermissionGroupName,0) ){ Log.i("antoon", permissionInfo.name); int appOp = AppOpsManager.permissionToOpCode(permissionInfo.name); int result = appOpsManager.checkOp(appOp, pkgInfo.applicationInfo.uid, pkgInfo.packageName); Log.e("antoon", "result = " + result); resultCount += result; } if(resultCount > 1){ handler.post(showPermissonCheck); } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } }