/* * Copyright (C) 2015-present, Ant Financial Services Group * * 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.alipay.hulu.common.utils.activity; import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.media.projection.MediaProjectionManager; import android.os.Build; import android.os.Bundle; import android.os.LocaleList; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.text.Html; import android.view.Display; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import com.alipay.hulu.common.R; import com.alipay.hulu.common.application.LauncherApplication; import com.alipay.hulu.common.constant.Constant; import com.alipay.hulu.common.injector.InjectorService; import com.alipay.hulu.common.injector.param.SubscribeParamEnum; import com.alipay.hulu.common.service.SPService; import com.alipay.hulu.common.tools.BackgroundExecutor; import com.alipay.hulu.common.tools.CmdTools; import com.alipay.hulu.common.utils.Callback; import com.alipay.hulu.common.utils.ContextUtil; import com.alipay.hulu.common.utils.LogUtil; import com.alipay.hulu.common.utils.MiscUtil; import com.alipay.hulu.common.utils.PermissionUtil; import com.alipay.hulu.common.utils.StringUtil; import com.android.permission.FloatWindowManager; import com.android.permission.rom.MiuiUtils; import com.android.permission.rom.RomUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by qiaoruikai on 2018/10/15 5:20 PM. */ public class PermissionDialogActivity extends Activity implements View.OnClickListener { private static final String TAG = "PermissionDialog"; public static final String PERMISSIONS_KEY = "permissions"; public static final String PERMISSION_IDX_KEY = "permissionIdx"; private static final String PERMISSION_SKIP_RECORD = "skipRecord"; private static final String PERMISSION_GRANT_RECORD = "grantRecord"; private static final String PERMISSION_GRANT_ADB = "grantAdb"; public static final int PERMISSION_FLOAT = 1; public static final int PERMISSION_ADB = 2; public static final int PERMISSION_ROOT = 3; public static final int PERMISSION_TOAST = 4; public static final int PERMISSION_ACCESSIBILITY = 5; public static final int PERMISSION_USAGE = 6; public static final int PERMISSION_RECORD = 7; public static final int PERMISSION_ANDROID = 8; public static final int PERMISSION_DYNAMIC = 9; public static final int PERMISSION_BACKGROUND = 10; public static volatile boolean runningStatus = false; private InjectorService injectorService; private TextView permissionPassed; private TextView permissionTotal; private ProgressBar progressBar; private TextView permissionText; private LinearLayout actionLayout; private LinearLayout positiveButton; private TextView positiveBtnText; private LinearLayout negativeButton; private TextView negativeBtnText; private LinearLayout thirdButton; private TextView thirdBtnText; private int currentIdx; private int totalIdx; private int USAGE_REQUEST = 10001; private int ACCESSIBILITY_REQUEST = 10002; private int M_PERMISSION_REQUEST = 10003; private int MEDIA_PROJECTION_REQUEST = 10004; private List<GroupPermission> allPermissions; private int currentPermissionIdx; /** * 权限名称映射表 */ public static Map<String, Integer> PERMISSION_NAMES = new HashMap<String, Integer>() { { put(Manifest.permission.READ_CALENDAR, R.string.permission__read_calendar); put(Manifest.permission.WRITE_CALENDAR, R.string.permission__write_calendar); put(Manifest.permission.CAMERA, R.string.permission__camera); put(Manifest.permission.READ_CONTACTS, R.string.permission__read_contacts); put(Manifest.permission.WRITE_CONTACTS, R.string.permission__write_contacts); put(Manifest.permission.GET_ACCOUNTS, R.string.permission__get_accounts); put(Manifest.permission.ACCESS_FINE_LOCATION, R.string.permission__access_fine_location); put(Manifest.permission.ACCESS_COARSE_LOCATION, R.string.permission__access_coarse_location); put(Manifest.permission.RECORD_AUDIO, R.string.permission__record_audio); put(Manifest.permission.READ_PHONE_STATE, R.string.permission__read_phone_state); put(Manifest.permission.CALL_PHONE, R.string.permission__call_phone); put(Manifest.permission.READ_CALL_LOG, R.string.permission__read_call_log); put(Manifest.permission.WRITE_CALL_LOG, R.string.permission__write_call_log); put(Manifest.permission.ADD_VOICEMAIL, R.string.permission__add_voicemail); put(Manifest.permission.USE_SIP, R.string.permission__use_sip); put(Manifest.permission.BODY_SENSORS, R.string.permission__body_sensors); put(Manifest.permission.SEND_SMS, R.string.permission__send_sms); put(Manifest.permission.RECEIVE_SMS, R.string.permission__receive_sms); put(Manifest.permission.READ_SMS, R.string.permission__read_sms); put(Manifest.permission.RECEIVE_WAP_PUSH, R.string.permission__receive_wap_push); put(Manifest.permission.RECEIVE_MMS, R.string.permission__receive_mms); put(Manifest.permission.READ_EXTERNAL_STORAGE, R.string.permission__read_external_storage); put(Manifest.permission.WRITE_EXTERNAL_STORAGE, R.string.permission__write_external_storage); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setFinishOnTouchOutside(false); setContentView(R.layout.permission_dialog_layout); setupWindow(); injectorService = LauncherApplication.getInstance().findServiceByName(InjectorService.class.getName()); initView(); initControl(); } @Override public void onBackPressed() { finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, false, "取消授权"); } /** * 设置窗体信息 */ private void setupWindow() { WindowManager windowManager = getWindowManager(); Display display = windowManager.getDefaultDisplay(); WindowManager.LayoutParams params = getWindow().getAttributes(); params.width = display.getWidth() - ContextUtil.dip2px(this, 48); getWindow().setGravity(Gravity.CENTER); } @Override public void finish() { runningStatus = false; super.finish(); } @Override protected void onDestroy() { runningStatus = false; LogUtil.i(TAG, "权限弹窗Stop"); super.onDestroy(); } /** * 加载界面 */ private void initView() { permissionPassed = (TextView) findViewById(R.id.permission_success); permissionTotal = (TextView) findViewById(R.id.permission_all); progressBar = (ProgressBar) findViewById(R.id.permission_loading_progress); permissionText = (TextView) findViewById(R.id.permission_text); actionLayout = (LinearLayout) findViewById(R.id.permission_action_layout); positiveButton = (LinearLayout) findViewById(R.id.permission_positive_button); positiveBtnText = (TextView) positiveButton.getChildAt(0); negativeButton = (LinearLayout) findViewById(R.id.permission_negative_button); negativeBtnText = (TextView) negativeButton.getChildAt(0); thirdButton = (LinearLayout) findViewById(R.id.permission_third_button); thirdBtnText = (TextView) thirdButton.getChildAt(0); } private void initControl() { positiveButton.setOnClickListener(this); negativeButton.setOnClickListener(this); thirdButton.setOnClickListener(this); currentPermissionIdx = getIntent().getIntExtra(PERMISSION_IDX_KEY, -1); groupPermissions(); processPermission(); } /** * 权限分组 */ private void groupPermissions() { List<String> permissions = getIntent().getStringArrayListExtra(PERMISSIONS_KEY); Map<Integer, GroupPermission> currentPermissions = new LinkedHashMap<>(); // 按照分组过一遍 for (String permission : permissions) { int group; switch (permission) { case "float": group = PERMISSION_FLOAT; break; case "root": group = PERMISSION_ROOT; break; case "adb": group = PERMISSION_ADB; break; case Settings.ACTION_USAGE_ACCESS_SETTINGS: group = PERMISSION_USAGE; break; case Settings.ACTION_ACCESSIBILITY_SETTINGS: group = PERMISSION_ACCESSIBILITY; break; case "screenRecord": group = PERMISSION_RECORD; break; case "background": group = PERMISSION_BACKGROUND; break; default: if (permission.startsWith("Android=")) { group = PERMISSION_ANDROID; } else if (permission.startsWith("toast:")) { group = PERMISSION_TOAST; } else { group = PERMISSION_DYNAMIC; } break; } // 如果有同分组 GroupPermission permissionG = currentPermissions.get(group); if (permissionG == null) { permissionG = new GroupPermission(group); currentPermissions.put(group, permissionG); } permissionG.addPermission(permission); } // 设置下实际需要的权限 allPermissions = new ArrayList<>(currentPermissions.values()); } /** * 开始处理权限 */ public void processPermission() { if (allPermissions == null || allPermissions.size() == 0) { showAction(StringUtil.getString(R.string.permission_list_error), getString(R.string.constant__confirm), new Runnable() { @Override public void run() { finish(); } }); } currentIdx = -1; totalIdx = allPermissions.size(); // 设置待处理总数 permissionTotal.setText(StringUtil.toString(totalIdx)); // 开始处理权限 processedAction(); } /** * 处理单项权限 */ private void processSinglePermission() { final GroupPermission permission = allPermissions.get(currentIdx); // 按照权限组别处理 switch (permission.permissionType) { case PERMISSION_FLOAT: if(!processFloatPermission()) { return; } break; case PERMISSION_ROOT: if (!processRootPermission()) { return; } break; case PERMISSION_ADB: if (!processAdbPermission()) { return; } break; case PERMISSION_TOAST: if (!processToastPermission(permission)) { return; } break; case PERMISSION_USAGE: if (!processUsagePermission()) { return; } break; case PERMISSION_ACCESSIBILITY: if (!processAccessibilityPermission()) { return; } break; case PERMISSION_RECORD: if (!processRecordPermission()) { return; } break; case PERMISSION_ANDROID: if (!processAndroidVersionPermission(permission)) { return; } break; case PERMISSION_DYNAMIC: if (!processDynamicPermission(permission)) { return; } break; case PERMISSION_BACKGROUND: if (!processBackgroundPermission()) { return; } break; } // 成功的直接processed processedAction(); } /** * 悬浮窗权限判断 * @return */ private boolean processFloatPermission() { if (!FloatWindowManager.getInstance().checkPermission(this)) { showAction(StringUtil.getString(R.string.float_permission), getString(R.string.permission__i_grant), new Runnable() { @Override public void run() { if (FloatWindowManager.getInstance().checkPermission(PermissionDialogActivity.this)) { processedAction(); } else { LauncherApplication.toast(R.string.permission__no_float_permission); } } }, getString(R.string.constant__confirm), new Runnable() { @Override public void run() { FloatWindowManager.getInstance().applyPermissionDirect(PermissionDialogActivity.this); } }); return false; } return true; } /** * 判断root权限 * @return */ private boolean processRootPermission() { if (!CmdTools.isRooted()) { showAction(StringUtil.getString(R.string.root_permission), getString(R.string.constant__confirm), new Runnable() { @Override public void run() { finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, false, "该需要Root权限,请Root后使用"); } }); return false; } return true; } /** * 处理ADB权限 * @return */ private boolean processAdbPermission() { BackgroundExecutor.execute(new Runnable() { @Override public void run() { boolean status; if (SPService.getBoolean(PERMISSION_GRANT_ADB, false)) { status = CmdTools.generateConnection(); } else { status = CmdTools.isInitialized(); } if (!status) { showAction(StringUtil.getString(R.string.adb_permission), getString(R.string.constant__confirm), new Runnable() { @Override public void run() { SPService.putBoolean(PERMISSION_GRANT_ADB, true); progressBar.setVisibility(View.VISIBLE); permissionText.setText(R.string.adb_open_advice); positiveButton.setEnabled(false); BackgroundExecutor.execute(new Runnable() { @Override public void run() { boolean result; try { result = CmdTools.generateConnection(); } catch (Exception e) { LogUtil.e(TAG, "连接adb异常", e); result = false; } if (result) { runOnUiThread(new Runnable() { @Override public void run() { positiveButton.setEnabled(true); } }); processedAction(); } else { runOnUiThread(new Runnable() { @Override public void run() { progressBar.setVisibility(View.GONE); permissionText.setText(R.string.open_adb_permission_failed); positiveButton.setEnabled(true); } }); } } }); } }, getString(R.string.constant__cancel), new Runnable() { @Override public void run() { finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, false, "ADB连接失败"); } }); } else { processedAction(); } } }); // 因为需要socket通信,所以就直接返回失败 return false; } /** * 处理提示信息 * @param permissionG * @return */ private boolean processToastPermission(GroupPermission permissionG) { List<String> permissions = permissionG.permissions; final List<String> real = new ArrayList<>(permissions.size() + 1); for (String p: permissions) { String permission = p.substring(6); if (!SPService.getBoolean(permission, false)) { real.add(permission); } } if (!real.isEmpty()) { showAction(StringUtil.join("\n", real), getString(R.string.permission__i_know), new Runnable() { @Override public void run() { processedAction(); } }, getString(R.string.constant__no_inform), new Runnable() { @Override public void run() { for (String p: real) { SPService.putBoolean(p, true); } processedAction(); } }); return false; } return true; } /** * 处理使用情况权限 * @return */ private boolean processUsagePermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !PermissionUtil.isUsageStatPermissionOn(this)) { showAction(StringUtil.getString(R.string.device_usage_permission), getString(R.string.permission__i_grant), new Runnable() { @Override public void run() { if (PermissionUtil.isUsageStatPermissionOn(PermissionDialogActivity.this)) { processedAction(); } else { LauncherApplication.toast(R.string.permission__valid_fail); } } }, getString(R.string.constant__confirm), new Runnable() { @Override public void run() { Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivityForResult(intent, USAGE_REQUEST); } }); return false; } return true; } /** * 处理辅助功能权限 * @return */ private boolean processAccessibilityPermission() { final InjectorService service = LauncherApplication.getInstance().findServiceByName(InjectorService.class.getName()); // 没有注册上AccessibilityService,需要开辅助功能 if (service.getMessage(SubscribeParamEnum.ACCESSIBILITY_SERVICE, null) == null) { BackgroundExecutor.execute(new Runnable() { @Override public void run() { final CountDownLatch latch = new CountDownLatch(1); InjectorService.g().waitForMessage(SubscribeParamEnum.ACCESSIBILITY_SERVICE, new Callback<AccessibilityService>() { @Override public void onResult(AccessibilityService item) { latch.countDown(); } @Override public void onFailed() { latch.countDown(); } }); CmdTools.execHighPrivilegeCmd("settings put secure enabled_accessibility_services com.alipay.hulu/com.alipay.hulu.shared.event.accessibility.AccessibilityServiceImpl"); CmdTools.execHighPrivilegeCmd("settings put secure accessibility_enabled 1"); try { latch.await(2000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { LogUtil.e(TAG, "Catch java.lang.InterruptedException: " + e.getMessage(), e); } // 可能是因为UIAutomator、Instrument等工具影响,清理掉 if (InjectorService.g().getMessage(SubscribeParamEnum.ACCESSIBILITY_SERVICE, AccessibilityService.class) == null) { showAction(getString(R.string.permission__try_kil_uiautomator), getString(R.string.constant__cancel), new Runnable() { @Override public void run() { finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, false, "User cancel"); } }); restartAccessibilityService(); } LauncherApplication.getInstance().showToast(getString(R.string.permission__open_accessibility)); // 等2秒,确定消息发过来了 MiscUtil.sleep(2000); LauncherApplication.getInstance().runOnUiThread(new Runnable() { @Override public void run() { if (service.getMessage(SubscribeParamEnum.ACCESSIBILITY_SERVICE, null) != null) { processedAction(); } else { processAccessibilityByHand(injectorService); } } }); } }); return false; } return true; } /** * 手动处理辅助功能问题 * @param service */ private void processAccessibilityByHand(final InjectorService service) { showAction(StringUtil.getString(R.string.accessibility_permission), getString(R.string.permission__i_grant), new Runnable() { @Override public void run() { if (service.getMessage(SubscribeParamEnum.ACCESSIBILITY_SERVICE, null) != null) { processedAction(); } else { LauncherApplication.toast(R.string.permission__valid_fail); } } }, getString(R.string.constant__confirm), new Runnable() { @Override public void run() { Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); // | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivityForResult(intent, ACCESSIBILITY_REQUEST); } }, getString(R.string.permission__force_stop), new Runnable() { @Override public void run() { BackgroundExecutor.execute(new Runnable() { @Override public void run() { CmdTools.execHighPrivilegeCmd("am force-stop com.alipay.hulu && am force-stop com.alipay.hulu"); } }); } }); } /** * 处理录屏权限 * @return */ @SuppressWarnings("NewApi") private boolean processRecordPermission() { // 如果包含忽略录屏,直接跳过 if (SPService.getBoolean(PERMISSION_SKIP_RECORD, false)) { return true; } if (Build.VERSION.SDK_INT < 21) { showAction(StringUtil.getString(R.string.record_screen_android_version_error, Build.VERSION.SDK_INT), getString(R.string.constant__confirm), new Runnable() { @Override public void run() { SPService.putBoolean(PERMISSION_SKIP_RECORD, true); processedAction(); } }); return false; } if (injectorService.getMessage(Constant.EVENT_RECORD_SCREEN_CODE, Intent.class) == null) { MediaProjectionManager mMediaProjectionManager = (MediaProjectionManager) getApplicationContext().getSystemService(MEDIA_PROJECTION_SERVICE); final Intent intent = mMediaProjectionManager.createScreenCaptureIntent(); // 之前申请过,直接申请 if (SPService.getBoolean(PERMISSION_GRANT_RECORD, false)) { startActivityForResult(intent, MEDIA_PROJECTION_REQUEST); } showAction(StringUtil.getString(R.string.record_screen_permission), getString(R.string.permission__i_grant), new Runnable() { @Override public void run() { if (injectorService.getMessage(Constant.EVENT_RECORD_SCREEN_CODE, Intent.class) != null) { processedAction(); SPService.putBoolean(PERMISSION_GRANT_RECORD, true); } else { LauncherApplication.toast(R.string.permission__no_record_info); } } }, getString(R.string.constant__confirm), new Runnable() { @Override public void run() { startActivityForResult(intent, MEDIA_PROJECTION_REQUEST); } }); return false; } return true; } /** * 处理系统权限版本 * @param permission * @return */ private boolean processAndroidVersionPermission(GroupPermission permission) { int maxVersion = 0; // 计算需要的最高系统版本 for (String per: permission.permissions) { int currentMax = Integer.parseInt(per.substring(8)); if (currentMax > maxVersion) { maxVersion = currentMax; } } if (Build.VERSION.SDK_INT < maxVersion) { showAction(StringUtil.getString(R.string.android_version_error, maxVersion, Build.VERSION.SDK_INT), getString(R.string.constant__confirm), new Runnable() { @Override public void run() { finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, false, "系统版本过低"); } }); return false; } return true; } /** * 处理后台弹出界面权限 * @return */ private boolean processBackgroundPermission() { if (RomUtils.checkIsMiuiRom()) { final String content = getString(R.string.permission__open_background_permission); if (!SPService.getBoolean(content, false)) { showAction(content, getString(R.string.permission__opened), new Runnable() { @Override public void run() { SPService.putBoolean(content, true); processedAction(); } }, getString(R.string.permission__go_to_open), new Runnable() { @Override public void run() { MiuiUtils.applyMiuiPermission(PermissionDialogActivity.this); } }); return false; } } return true; } /** * 关闭Instrument和UIAutomator */ public static void cleanInstrumentationAndUiAutomator() { String allActions = CmdTools.execHighPrivilegeCmd("ps -ef | grep shell"); LogUtil.i(TAG, "Let me see::::" + allActions); // 关闭Instrument String result = CmdTools.execHighPrivilegeCmd("pm list instrumentation"); String[] lines = StringUtil.split(result, "\n"); Pattern pattern = Pattern.compile("\\(target=(.*)\\)"); String targetApp = InjectorService.g().getMessage(SubscribeParamEnum.APP, String.class); for(String line: lines) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { String instPkg = matcher.group(1); if (StringUtil.equals(instPkg, "com.alipay.hulu")) { continue; } // 不杀目标应用 if (StringUtil.equals(instPkg, targetApp)) { continue; } LauncherApplication.getInstance().showToast(StringUtil.getString(R.string.permission__kill_app, instPkg)); LogUtil.i(TAG, "Find instrumentation package and killing \"" + instPkg + "\""); String exeRes = CmdTools.execHighPrivilegeCmd("am force-stop " + instPkg); LogUtil.i(TAG, "force-stop result:::" + exeRes); CmdTools.execHighPrivilegeCmd("am force-stop " + instPkg); } } // 关闭UIAutomator String[] pids = CmdTools.ps("uiautomator"); for (String pid: pids) { LogUtil.i(TAG, "Get uiautomator pid line: " + pid); String[] columns = pid.split("\\s+"); if (columns.length > 2) { pid = columns[1]; CmdTools.execHighPrivilegeCmd("kill " + pid); } } // 杀掉Monkey pids = CmdTools.ps("monkey"); for (String pid: pids) { // 只杀掉shell用户开启的monkey if (!StringUtil.contains(pid, "shell")) { continue; } LogUtil.i(TAG, "Get Monkey pid line: " + pid); String[] columns = pid.split("\\s+"); if (columns.length > 2) { pid = columns[1]; CmdTools.execHighPrivilegeCmd("kill " + pid); } } } /** * 重启辅助功能 */ private void restartAccessibilityService() { LauncherApplication.getInstance().showToast(getString(R.string.permission__restarting_accessibility)); // 关uiautomator cleanInstrumentationAndUiAutomator(); // 提前点准备 final CountDownLatch latch = new CountDownLatch(1); InjectorService.g().waitForMessage(SubscribeParamEnum.ACCESSIBILITY_SERVICE, new Callback<AccessibilityService>() { @Override public void onResult(AccessibilityService item) { latch.countDown(); } @Override public void onFailed() { latch.countDown(); } }); // 切换回TalkBack CmdTools.execHighPrivilegeCmd("settings put secure enabled_accessibility_services com.android.talkback/com.google.android.marvin.talkback.TalkBackService"); // 等2秒 MiscUtil.sleep(2000); CmdTools.execHighPrivilegeCmd("settings put secure enabled_accessibility_services com.alipay.hulu/com.alipay.hulu.shared.event.accessibility.AccessibilityServiceImpl"); // 等待辅助功能重新激活 try { latch.await(20000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { LogUtil.e(TAG, "Catch java.lang.InterruptedException: " + e.getMessage(), e); } } @Override protected void onStart() { super.onStart(); runningStatus = true; } @Override protected void onStop() { super.onStop(); } /** * 处理需要动态授权的权限 */ private boolean processDynamicPermission(GroupPermission permission) { // 动态申请权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String[] requestPermissions = permission.permissions.toArray(new String[0]); // 看下哪些权限没有被授权 final List<String> ungrantedPermissions = PermissionUtil.checkUngrantedPermission(this, requestPermissions); if (ungrantedPermissions != null && ungrantedPermissions.size() > 0) { List<String> mappedName = new ArrayList<>(); for (String dynPermission: ungrantedPermissions) { Integer mapName = PERMISSION_NAMES.get(dynPermission); if (mapName != null) { mappedName.add(StringUtil.getString(mapName)); } else { mappedName.add(dynPermission); } } String permissionNames = StringUtil.join("、", mappedName); showAction(StringUtil.getString(R.string.request_dynamic_permission, permissionNames, ungrantedPermissions.size()), getString(R.string.constant__confirm), new Runnable() { @Override public void run() { ActivityCompat.requestPermissions(PermissionDialogActivity.this, ungrantedPermissions.toArray(new String[0]), M_PERMISSION_REQUEST); } }, getString(R.string.constant__cancel), new Runnable() { @Override public void run() { LogUtil.i(TAG, "用户取消授权"); finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, false, "用户不进行授权"); } }); return false; } } return true; } /** * 显示操作框 * @param message 显示文案 * @param positiveText 确定文案 * @param positiveAction 确定动作 */ private void showAction(String message, String positiveText, Runnable positiveAction) { showAction(message, positiveText, positiveAction, null, null); } /** * 显示操作框 * @see #showAction(String, String, Runnable, String, Runnable, String, Runnable) */ private void showAction(final String message, final String positiveText, final Runnable positiveAct, final String negativeText, final Runnable negativeAct) { showAction(message, positiveText, positiveAct, negativeText, negativeAct, null, null); } /** * 显示操作框 * @param message 显示文案 * @param positiveText 确定文案 * @param positiveAct 确定动作 * @param negativeText 取消文案 * @param negativeAct 取消动作 * @param thirdText 第三操作文案 * @param thirdAct 第三操作 */ private void showAction(final String message, final String positiveText, final Runnable positiveAct, final String negativeText, final Runnable negativeAct, final String thirdText, final Runnable thirdAct) { runOnUiThread(new Runnable() { @Override public void run() { positiveAction = positiveAct; negativeAction = negativeAct; thirdAction = thirdAct; progressBar.setVisibility(View.GONE); actionLayout.setVisibility(View.VISIBLE); // 显示文字 permissionText.setText(Html.fromHtml(StringUtil.patternReplace(message, "\n", "<br/>"))); // 设置按钮文本 positiveBtnText.setText(positiveText); // 如果取消非空 if (!StringUtil.isEmpty(negativeText)) { negativeButton.setVisibility(View.VISIBLE); negativeBtnText.setText(negativeText); } else { negativeButton.setVisibility(View.GONE); } if (!StringUtil.isEmpty(thirdText)) { thirdButton.setVisibility(View.VISIBLE); thirdBtnText.setText(thirdText); } else { thirdButton.setVisibility(View.GONE); } } }); } /** * 当前权限已处理完毕 */ private void processedAction() { currentIdx++; runOnUiThread(new Runnable() { @Override public void run() { progressBar.setVisibility(View.VISIBLE); actionLayout.setVisibility(View.GONE); permissionPassed.setText(StringUtil.toString(currentIdx + 1)); if (currentIdx >= totalIdx) { finish(); PermissionUtil.onPermissionResult(currentPermissionIdx, true, null); return; } // 开始处理下一条权限 processSinglePermission(); } }); } private Runnable positiveAction; private Runnable negativeAction; private Runnable thirdAction; @Override public void onClick(View v) { if (v == positiveButton) { if (positiveAction != null) { positiveAction.run(); } } else if (v == negativeButton) { if (negativeAction != null) { negativeAction.run(); } } else if (v == thirdButton) { if (thirdAction != null) { thirdAction.run(); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == USAGE_REQUEST) { currentIdx --; processedAction(); } else if (requestCode == MEDIA_PROJECTION_REQUEST && resultCode == RESULT_OK) { LogUtil.d(TAG, "获取录屏许可,录屏响应码:" + resultCode); injectorService.pushMessage(Constant.EVENT_RECORD_SCREEN_CODE, data); processedAction(); SPService.putBoolean(PERMISSION_GRANT_RECORD, true); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == M_PERMISSION_REQUEST) { for (int i = 0; i < grantResults.length; i++) { int result = grantResults[i]; if (result != PackageManager.PERMISSION_GRANTED) { LogUtil.i(TAG, "用户不授权%s权限", permissions[i]); // 重新去检查权限 processSinglePermission(); return; } } processedAction(); } } @Override protected void attachBaseContext(Context newBase) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { newBase = updateResources(newBase); } super.attachBaseContext(newBase); } @TargetApi(Build.VERSION_CODES.N) private static Context updateResources(Context context) { Resources resources = context.getResources(); Locale locale = LauncherApplication.getInstance().getLanguageLocale(); Configuration configuration = resources.getConfiguration(); configuration.setLocale(locale); configuration.setLocales(new LocaleList(locale)); return context.createConfigurationContext(configuration); } /** * 权限分组 */ private static class GroupPermission { private int permissionType; private List<String> permissions; private GroupPermission(int permissionType) { this.permissionType = permissionType; } /** * 添加一条权限 * @param permission */ private void addPermission(String permission) { if (permissions == null) { permissions = new ArrayList<>(); } if (!permissions.contains(permission)) { permissions.add(permission); } else { LogUtil.w(TAG, "Permission %s already added", permission); } } } }