package com.robotium.solo; import android.app.Activity; import android.app.Instrumentation; import android.app.UiAutomation; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import java.util.ArrayList; import java.util.List; import static com.robotium.solo.Solo.LOG_TAG; class Permission { /** * CALENDAR **/ private static final String READ_CALENDAR = "android.permission.READ_CALENDAR"; private static final String WRITE_CALENDAR = "android.permission.WRITE_CALENDAR"; /** * CAMERA **/ private static final String CAMERA = "android.permission.CAMERA"; /** * CONTACTS **/ private static final String READ_CONTACTS = "android.permission.READ_CONTACTS"; private static final String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS"; private static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; /** * LOCATION **/ private static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"; private static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION"; /** * AUDIO **/ private static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; /** * PHONE **/ private static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; private static final String CALL_PHONE = "android.permission.CALL_PHONE"; private static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG"; private static final String WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG"; private static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL"; private static final String USE_SIP = "android.permission.USE_SIP"; private static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS"; /** * SENSORS **/ private static final String BODY_SENSORS = "android.permission.BODY_SENSORS"; /** * SMS **/ private static final String SEND_SMS = "android.permission.SEND_SMS"; private static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS"; private static final String READ_SMS = "android.permission.READ_SMS"; private static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"; private static final String RECEIVE_MMS = "android.permission.RECEIVE_MMS"; private static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; /** * SD Card **/ private static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE"; public static final String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; /** * Package Installer */ private static final String PACKAGE_INSTALLER = "com.android.packageinstaller"; private static final String PERMISSION_ALLOW_ID = "com.android.packageinstaller:id/permission_allow_button"; private static final String PACKAGE_INSTALLER_XIAOMI = "com.lbe.security.miui"; private static final String PERMISSION_ALLOW_ID_XIAOMI = "android:id/button1"; private static final String[] PermissionGroup = new String[]{READ_CALENDAR, WRITE_CALENDAR, CAMERA, READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, RECORD_AUDIO, READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG, WRITE_CALL_LOG, ADD_VOICEMAIL, USE_SIP, PROCESS_OUTGOING_CALLS, BODY_SENSORS, SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_WAP_PUSH, RECEIVE_MMS, READ_CELL_BROADCASTS, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE}; private Context context; private String pkg; private Instrumentation instrumentation; Permission(Context context, String pkg, Instrumentation instrumentation){ this.context = context; this.pkg = pkg; this.instrumentation = instrumentation; } /** * Returns Manufacturer. */ private String getManufacturer(){ return Build.MANUFACTURER; } /** * Requests permissions to be granted to this application. */ void requestPermissions(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String[] permissions = checkPermissions(); if (permissions == null || permissions.length == 0) return; final String manufacturer = getManufacturer(); ActivityCompat.requestPermissions((Activity) context, permissions, 10000); UiAutomation uiAutomation = instrumentation.getUiAutomation(); uiAutomation.setOnAccessibilityEventListener(new UiAutomation.OnAccessibilityEventListener() { @Override public void onAccessibilityEvent(AccessibilityEvent event) { android.util.Log.d(LOG_TAG, "UiAutomation: " + event.toString()); if (manufacturer.toLowerCase().contains("mi")) { handlePermissions(event, PACKAGE_INSTALLER_XIAOMI, PERMISSION_ALLOW_ID_XIAOMI); } else handlePermissions(event, PACKAGE_INSTALLER, PERMISSION_ALLOW_ID); } }); } } /** * Requests permissions to be granted to this application. * adb shell pm grant package android.permission.* */ void requestPermissionsForShell() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String[] permissions = checkPermissions(); if (permissions == null) return; UiAutomation uiAutomation = instrumentation.getUiAutomation(); for (String permission: permissions) { uiAutomation.executeShellCommand("pm grant " + pkg + " " + permission); } } } private void handlePermissions(AccessibilityEvent event, String packageInstaller, String permissionAllowId) { if (packageInstaller.contains(event.getPackageName())) { if (event.getSource() != null) { List<AccessibilityNodeInfo> infoList = event.getSource().findAccessibilityNodeInfosByViewId(permissionAllowId); if (infoList == null || infoList.isEmpty()) return; performClick(infoList.get(0)); } } } private void performClick(AccessibilityNodeInfo nodeInfo) { if(nodeInfo == null){ Log.w(LOG_TAG, "performClick: nodeInfo is null."); return; } if(nodeInfo.isClickable()) nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); else performClick(nodeInfo.getParent()); } /** * Check Permissions, if permission denied add to requestPermissions. * @return requestPermissions */ private String[] checkPermissions(){ ArrayList<String> requestPermissions = new ArrayList<>(); String[] permissions = filterPermissions(); if (permissions == null) return null; for (String p: permissions) { int mPermission = ContextCompat.checkSelfPermission(context, p); if (mPermission != PackageManager.PERMISSION_GRANTED) requestPermissions.add(p); } return requestPermissions.toArray(new String[requestPermissions.size()]); } /** * Filter Permissions * @return Permissions */ private String[] filterPermissions(){ ArrayList<String> filter = new ArrayList<>(); String[] allPermissions = getAllPermissions(context, pkg); if (allPermissions == null) return null; for (String permission: PermissionGroup) { for (String s: allPermissions) { if (permission.contains(s)) filter.add(permission); } } return filter.toArray(new String[filter.size()]); } /** * Get target package requestedPermissions. * @param context context * @param pkg target package * @return Permissions */ private String[] getAllPermissions(Context context, String pkg){ try { PackageManager pm = context.getPackageManager(); PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS); return info.requestedPermissions; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return null; } }