和上次获取设备序列号一样,仍然是通过无障碍服务实现,在之前的代码基础上做了更新。代码和demo如下:
package com.zwxuf.lib.devicehelper;import android.accessibilityservice.AccessibilityService;
import android.app.Activity;
import android.app.Application;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class DeviceHelper implements Application.ActivityLifecycleCallbacks {static final String TAG = "WADQ_DeviceHelper";static final String ACTION_ACQUIRE_SERIAL_SUCCESS = "zwxuf.intent.action.ACQUIRE_SERIAL_SUCCESS";static final String ACTION_ACQUIRE_PHONE_SUCCESS = "zwxuf.intent.action.ACQUIRE_PHONE_SUCCESS";private static Handler mHandler = new Handler(Looper.getMainLooper());private boolean isMsgReceiverEnabled;private OnAcquireSerialListener mOnAcquireSerialListener;private OnAcquirePhoneListener onAcquirePhoneListener;private Activity mActivity;private Application mApplication;public DeviceHelper(Activity mActivity) {this.mActivity = mActivity;mApplication = mActivity.getApplication();mApplication.registerActivityLifecycleCallbacks(this);}public void acquireSerial(OnAcquireSerialListener listener) {mOnAcquireSerialListener = listener;if (!isMsgReceiverEnabled) initMsgReceiver();AcquireSerialService.isSerialFound = false;AcquireSerialService.isStatusInfoFound = false;Intent intent = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mActivity.startActivity(intent);}public void acquirePhone(OnAcquirePhoneListener listener) {onAcquirePhoneListener = listener;if (!isMsgReceiverEnabled) initMsgReceiver();Intent intent = new Intent();intent.setClassName("com.android.phone", "com.android.phone.MSimMobileNetworkSettings");intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);try {mActivity.startActivity(intent);} catch (Exception e) {e.printStackTrace();Toast.makeText(mActivity, e.toString(), Toast.LENGTH_SHORT).show();}}private void releaseAcquireSerial() {List<Service> services = getServices();for (Service service : services) {if (service instanceof AcquireSerialService) {((AcquireSerialService) service).release();break;}}}private void releaseAcquirePhone() {List<Service> services = getServices();for (Service service : services) {if (service instanceof AcquirePhoneService) {((AcquirePhoneService) service).release();break;}}}private void initMsgReceiver() {IntentFilter filter = new IntentFilter();filter.addAction(ACTION_ACQUIRE_SERIAL_SUCCESS);filter.addAction(ACTION_ACQUIRE_PHONE_SUCCESS);mActivity.registerReceiver(mMsgReceiver, filter);isMsgReceiverEnabled = true;}private BroadcastReceiver mMsgReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (ACTION_ACQUIRE_SERIAL_SUCCESS.equals(intent.getAction())) {String serial = intent.getStringExtra("serial");if (mOnAcquireSerialListener != null) {mOnAcquireSerialListener.onAcquireSerial(serial);}} else if (ACTION_ACQUIRE_PHONE_SUCCESS.equals(intent.getAction())) {ArrayList<String> phoneNumbers = intent.getStringArrayListExtra("phones");if (onAcquirePhoneListener != null) {onAcquirePhoneListener.onAcquirePhone(phoneNumbers);}}releaseMsgReciever();}};private void releaseMsgReciever() {if (isMsgReceiverEnabled) {mActivity.unregisterReceiver(mMsgReceiver);isMsgReceiverEnabled = false;}}public void release() {releaseMsgReciever();mApplication.unregisterActivityLifecycleCallbacks(this);releaseAcquireSerial();releaseAcquirePhone();}public boolean canAcquireSerial() {return isServiceEnabled(mActivity, AcquireSerialService.class);}public boolean canAcquirePhone() {return isServiceEnabled(mActivity, AcquirePhoneService.class);}public void openAccessibilitySettings(final int requestCode) {Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);try {mActivity.startActivityForResult(intent, requestCode);} catch (Exception e) {e.printStackTrace();}}private static boolean isServiceEnabled(Context context, Class<? extends AccessibilityService> serviceClass) {if (serviceClass == null) {return false;}String serviceName = context.getPackageName() + "/" + serviceClass.getName();try {int enabled = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);if (enabled == 1) {String service = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);Log.i(TAG, service);return service != null && service.contains(serviceName);}} catch (Exception e) {e.printStackTrace();}return false;}static Handler getHandler() {return mHandler;}@Overridepublic void onActivityCreated(Activity activity, Bundle savedInstanceState) {}@Overridepublic void onActivityStarted(Activity activity) {}@Overridepublic void onActivityResumed(Activity activity) {}@Overridepublic void onActivityPaused(Activity activity) {}@Overridepublic void onActivityStopped(Activity activity) {}@Overridepublic void onActivitySaveInstanceState(Activity activity, Bundle outState) {}@Overridepublic void onActivityDestroyed(Activity activity) {if (activity == mActivity) {release();}}private static List<Service> getServices() {List<Service> services = new ArrayList<>();Object mActivityThread = getActivityThread();try {Class mActivityThreadClass = mActivityThread.getClass();Field mServicesField = mActivityThreadClass.getDeclaredField("mServices");mServicesField.setAccessible(true);Object mServices = mServicesField.get(mActivityThread);if (mServices instanceof Map) {Map<IBinder, Service> arrayMap = (Map) mServices;for (Map.Entry<IBinder, Service> entry : arrayMap.entrySet()) {Service service = entry.getValue();if (service != null) {services.add(service);}}}} catch (Throwable e) {e.printStackTrace();}return services;}private static Object getActivityThread() {try {Class ActivityThread = Class.forName("android.app.ActivityThread");Method currentActivityThread = ActivityThread.getMethod("currentActivityThread");currentActivityThread.setAccessible(true);return currentActivityThread.invoke(null);} catch (Throwable e) {e.printStackTrace();}return null;}}
获取手机号服务代码:
package com.zwxuf.lib.devicehelper;import android.accessibilityservice.AccessibilityService;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;import java.util.AbstractList;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class AcquirePhoneService extends AccessibilityService {private ArrayList<String> mPhoneNumbers = new ArrayList<>();private boolean mAcquireSuccess;@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {if (event.getPackageName() == null || event.getClassName() == null) {return;}String packageName = event.getPackageName().toString();String className = event.getClassName().toString();final AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if (nodeInfo != null) {if (!packageName.equals(getApplicationContext().getPackageName())) {enumChildNodeInfo(nodeInfo, 0);}}}@Overridepublic void onInterrupt() {}private void enumChildNodeInfo(AccessibilityNodeInfo nodeInfo, int level) {//Dbg.print(TAG, StringUtils.generateStr(" ", level), nodeInfo.getClassName(), getNodeText(nodeInfo), nodeInfo.getViewIdResourceName());int count = nodeInfo.getChildCount();//Dbg.print("count=" + count);if (count > 0) {for (int i = 0; i < count; i++) {final AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);if (childNodeInfo == null) continue;/*if (childNodeInfo.isScrollable()) {childNodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);}*/List<AccessibilityNodeInfo> nodeInfoList = childNodeInfo.findAccessibilityNodeInfosByViewId("android:id/title");if (nodeInfoList != null && !nodeInfoList.isEmpty()) {for (AccessibilityNodeInfo ni : nodeInfoList) {String text = getNodeText(ni);if (text == null) continue;if (text.startsWith("卡 1") || text.startsWith("卡 2")) {int start = text.lastIndexOf("(");int end = text.indexOf(")", start);if (start > 0 && start < end) {String number = text.substring(start + 1, end);if (number.startsWith("+86")) {number = number.substring(3);}if (isPhoneNumber(number) && !mPhoneNumbers.contains(number)) {mPhoneNumbers.add(number);}}if (!mPhoneNumbers.isEmpty() && !mAcquireSuccess) {mAcquireSuccess = true;//延时获取第2个手机号DeviceHelper.getHandler().postDelayed(new Runnable() {@Overridepublic void run() {Intent intent = new Intent(DeviceHelper.ACTION_ACQUIRE_PHONE_SUCCESS);intent.putExtra("phones", mPhoneNumbers);sendBroadcast(intent);performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);release();}}, 500);}break;}}}enumChildNodeInfo(childNodeInfo, level + 1);}}nodeInfo.recycle();}private String getNodeText(AccessibilityNodeInfo nodeInfo) {if (nodeInfo != null && nodeInfo.getText() != null) {return nodeInfo.getText().toString();} else {return null;}}static boolean isPhoneNumber(String mobiles) {Pattern p = Pattern.compile("^(0|86|17951)?(13[0-9]|15[0-9]|17[0-9]|18[0-9]|14[0-9]|16[0-9]|19[0-9])[0-9]{8}$");Matcher m = p.matcher(mobiles);return m.matches();}public void release() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {disableSelf();}}
}
下载地址: