Android10以上實現獲取設備序列號功能

Android10以上實現獲取設備唯一標識,目前只支持華為和榮耀設備。實現原理:通過無障礙服務讀取序列號界面。

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";private static Handler mHandler = new Handler(Looper.getMainLooper());private boolean isMsgReceiverEnabled;private OnAcquireSerialListener mOnAcquireSerialListener;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);}private void releaseAcquireSerial() {List<Service> services = getServices();for (Service service : services) {if (service instanceof AcquireSerialService) {((AcquireSerialService) service).release();break;}}}private void initMsgReceiver() {IntentFilter filter = new IntentFilter(ACTION_ACQUIRE_SERIAL_SUCCESS);mActivity.registerReceiver(mMsgReceiver, filter);isMsgReceiverEnabled = true;}private BroadcastReceiver mMsgReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String serial = intent.getStringExtra("serial");if (mOnAcquireSerialListener != null) {mOnAcquireSerialListener.onAcquireSerial(serial);}releaseMsgReciever();}};private void releaseMsgReciever() {if (isMsgReceiverEnabled) {mActivity.unregisterReceiver(mMsgReceiver);isMsgReceiverEnabled = false;}}public void release() {releaseMsgReciever();mApplication.unregisterActivityLifecycleCallbacks(this);releaseAcquireSerial();}public boolean canAcquireSerial() {return isServiceEnabled(mActivity, AcquireSerialService.class);}public void openAcquireSerialSettings(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;}}
public class AcquireSerialService extends AccessibilityService {static boolean isStatusInfoFound;static boolean isSerialFound;@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(packageName, nodeInfo, 0);}}}@Overridepublic void onInterrupt() {}private Runnable mScrollRunnalbe;private void enumChildNodeInfo(String packageName, AccessibilityNodeInfo nodeInfo, int level) {int count = nodeInfo.getChildCount();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);}if (!isSerialFound) {String serial = getSerialByNodeInfo(packageName, childNodeInfo);if (serial != null && !serial.isEmpty()) {//獲取到snLog.i(DeviceHelper.TAG, serial);Intent intent = new Intent(DeviceHelper.ACTION_ACQUIRE_SERIAL_SUCCESS);intent.putExtra("serial", serial);sendBroadcast(intent);performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);DeviceHelper.getHandler().postDelayed(new Runnable() {@Overridepublic void run() {performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);release();}}, 200);return;}enumChildNodeInfo(packageName, childNodeInfo, level + 1);}}}nodeInfo.recycle();}private String getSerialByNodeInfo(String packageName, AccessibilityNodeInfo nodeInfo) {if (nodeInfo.getText() == null) {return null;}String text = nodeInfo.getText().toString();if (text.equals("序列號")) {isStatusInfoFound = true;isSerialFound = true;if (mScrollRunnalbe != null) {DeviceHelper.getHandler().removeCallbacks(mScrollRunnalbe);mScrollRunnalbe = null;}return getValue(nodeInfo);} else if (packageName.equals("com.android.settings") && (text.equals("狀態信息") || text.equals("狀態消息")) && !isStatusInfoFound) {isStatusInfoFound = true;AccessibilityNodeInfo statusInfoParent = nodeInfo.getParent();while (statusInfoParent != null && !statusInfoParent.isClickable()) {statusInfoParent = statusInfoParent.getParent();}if (statusInfoParent != null) {final AccessibilityNodeInfo finalStatusInfoParent = statusInfoParent;DeviceHelper.getHandler().postDelayed(new Runnable() {@Overridepublic void run() {finalStatusInfoParent.performAction(AccessibilityNodeInfo.ACTION_CLICK);}}, 200);}}return null;}private String getValue(AccessibilityNodeInfo nodeInfo) {AccessibilityNodeInfo snLayout = nodeInfo.getParent();if (snLayout != null) {while (true) {List<AccessibilityNodeInfo> snSummaryList = snLayout.findAccessibilityNodeInfosByViewId("android:id/summary");if (snSummaryList != null && !snSummaryList.isEmpty()) {AccessibilityNodeInfo snSummary = snSummaryList.get(0);if (snSummary != null && snSummary.getText() != null) {return snSummary.getText().toString();}}snLayout = snLayout.getParent();if (snLayout == null) {break;}}}return null;}private String getNodeText(AccessibilityNodeInfo nodeInfo) {if (nodeInfo != null && nodeInfo.getText() != null) {return nodeInfo.getText().toString();} else {return null;}}public void release() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {disableSelf();}}
}

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private DeviceHelper mDeviceHelper;private TextView tv_serial, tv_phone;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_serial = findViewById(R.id.tv_serial);mDeviceHelper = new DeviceHelper(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.bn_get_serial:getSerial();break;}}private void getSerial() {if (!mDeviceHelper.canAcquireSerial()) {new AlertDialog.Builder(this).setMessage("沒有開啟無障礙服務").setPositiveButton("去開啟", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {mDeviceHelper.openAcquireSerialSettings(1000);}}).setNegativeButton("取消", null).create().show();return;}mDeviceHelper.acquireSerial(new OnAcquireSerialListener() {@Overridepublic void onAcquireSerial(String serial) {//Toast.makeText(MainActivity.this, serial, Toast.LENGTH_SHORT).show();tv_serial.setText("sn:" + serial);}});}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/40923.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/40923.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/40923.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Zoom使用的基本步驟和注意事項

Zoom是一款功能強大的視頻會議軟件&#xff0c;廣泛應用于遠程辦公、在線教育、團隊協作等多個場景。以下是Zoom使用的基本步驟和注意事項&#xff1a; 一、注冊與登錄 注冊Zoom賬戶&#xff1a; 訪問Zoom官方網站&#xff08;如zoom.us&#xff09;&#xff0c;點擊“注冊”…

Android Enable 和clickable

setEnabled 使能控件 設置為false&#xff0c;該控件永遠不會活動&#xff0c;不管設置為什么屬性&#xff0c;都無效&#xff1b; 設置為true&#xff0c;表明激活該控件&#xff0c;控件處于活動狀態&#xff0c;處于活動狀態&#xff0c;就能響應事件了&#xff0c;比如觸摸…

mybatis實現動態sql

第一章、動態SQL MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗&#xff0c;你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記添加必要的空格&#xff0c;還要注意去掉列表最后一個列名的逗號。利用動態 SQL 這一特…

2024北京大健康展,北京健康生活產品展覽會十月舉辦

2024北京健博會&#xff0c;立足北京&#xff0c;效應輻射全國買方市場&#xff0c;助力健康中國事業建設&#xff1b; 2024第11屆中國&#xff08;北京&#xff09;國際大健康產業博覽會 The 2024 China (Beijing) International Health Service Expo 時間&#xff1a;2024年…

華為 RIP 協議中 RIP 兼容版本、RIPv1、RIPv2 在收發 RIP 報文時的區別

華為 RIP 協議中 RIP 兼容版本、RIPv1、RIPv2 的區別 為了更好地支持實際環境中路由器對 RIP 的支持&#xff0c;華為 VRP 平臺具有一個兼容版本&#xff0c;默認情況下啟動 RIP 進程后&#xff0c;如果沒有配置 RIP 版本&#xff0c;該版本就為兼容版本&#xff0c;對 versio…

[ C++ ] 深入理解模板( 進 階 )

目錄 非類型模板參數 類模板沒有實例化的情況 模板的特化 注意函數特化中遇到的問題 建議&#xff1a;&#xff08;直接使用函數重載&#xff09; 類模板特化 全特化 偏特化 偏特化有以下兩種表現方式&#xff1a; 部分特化&#xff08;將模板參數類表中的一部分參數特化…

vue this.$refs加變量名

想動態獲取$refs&#xff0c;我們可以用模板字符串來動態綁定ref的值。代碼如下&#xff1a; this.$refs[${this.treeQueFlag}].setCheckedNodes([]); $refs后面拼變量&#xff0c;vue動態給$refs賦值_vue ref動態賦值-CSDN博客

旅游系統(附管理端+前臺)PHP源碼

一. 前言 今天小編給大家帶來了一款可學習&#xff0c;可商用的&#xff0c;旅游系統 源碼&#xff0c;支持二開&#xff0c;無加密。支持景點管理&#xff0c;登錄&#xff0c;景點預定&#xff0c;意見反饋&#xff0c;統計等功能。詳細界面和功能見下面視頻演示。 二. 視頻…

【flutter問題記錄】 無效的源發行版:17

問題描述 在看開源項目的時候&#xff0c;clone下來后一直編譯失敗&#xff0c;提示&#xff1a;無效的源發行版:17&#xff0c;看描述大概是jdk的版本問題&#xff0c;但是在Android studio各種指定都無用&#xff0c;網上資料也沒有flutter項目的解決方案&#xff0c;最后在…

在Spring MVC框架中,如何處理HTTP請求和響應?

在Spring MVC框架中&#xff0c;HTTP請求和響應的處理是通過一系列組件和流程來完成的。以下是Spring MVC處理HTTP請求和響應的主要步驟&#xff1a; 用戶發起請求&#xff1a; 用戶在客戶端&#xff08;如瀏覽器&#xff09;上發起一個HTTP請求&#xff0c;這個請求被發送到服…

廣州自閉癥機構哪家好?

在廣州&#xff0c;眾多的自閉癥康復機構中&#xff0c;星貝育園自閉癥兒童康復學校以其獨特的優勢脫穎而出。 一、專業的師資團隊 我們擁有一支經驗豐富、專業素養極高的師資隊伍。每位老師都經過嚴格的專業培訓&#xff0c;深入了解自閉癥兒童的特點和需求。他們不僅具…

深入挖掘海外快手kwai ads推廣巴西slots手游廣告獨家優勢

深入挖掘海外快手kwai ads推廣巴西slots手游廣告獨家優勢 在數字化時代&#xff0c;廣告投放已成為各行各業不可或缺的一部分&#xff0c;特別是在游戲行業&#xff0c;如何有效地推廣游戲產品&#xff0c;吸引玩家的眼球&#xff0c;成為了每一個游戲開發商和廣告主所關注的焦…

假設性文檔嵌入 HyDE:大模型 + 對比學習,從關鍵詞相似度搜索到語義搜索

假設性文檔嵌入 HyDE&#xff1a;大模型 對比學習&#xff0c;從關鍵詞相似度搜索到語義搜索 提出背景流程圖解法拆解類比1. 單一文檔嵌入空間的搜索2. 指令跟隨型語言模型&#xff08;InstructLM&#xff09;的引入3. 生成文檔的嵌入編碼 提出背景 論文&#xff1a;https://…

python怎么樣將一段程序無效掉

1、python中可以用注釋屏蔽一段語句&#xff0c;具體方法如下&#xff0c;首先打開一段python的示例程序&#xff1a; 2、然后單行注釋的方法是在語句前面加上#&#xff0c;程序運行后添加注釋的地方的語句會被自動跳過&#xff0c;這里可以看到將打印變量a的語句添加注釋就沒有…

vue處理重復請求

處理方法記錄第一次的請求時間-后面的請求時間&#xff0c;判斷間隔時間提示請求重復 // 登錄方法 定義repeatSubmit屬性控制是否重復請求 export function login(username, password, code, uuid) {const data {username,password,code,uuid}return request({url: /login,he…

前端css性能優化

前端css性能優化 1. 減少樣式表數量和壓縮文件大小&#xff1a; 通過合并多個樣式表、刪除未使用的樣式、壓縮樣式表等方式來減少樣式表數量和大小&#xff0c;從而減少網絡請求和提高加載速度。 通常來說&#xff0c;樣式文件會被瀏覽器緩存&#xff0c;進入到其他頁面樣式文件…

在 C++中,如何實現高效的多線程并發編程以處理大規模數據計算,同時避免常見的競態條件和死鎖問題?

在 C 中&#xff0c;可以使用以下幾種方法來實現高效的多線程并發編程以處理大規模數據計算&#xff0c;并避免常見的競態條件和死鎖問題&#xff1a; 使用互斥鎖&#xff1a;使用 std::mutex 類型的互斥鎖來保護共享數據的訪問。在訪問共享數據之前&#xff0c;線程先要獲取互…

二叉樹 Leetcode 101 對稱二叉樹

二叉樹 Leetcode 101 對稱二叉樹 Leetcode 101 要點&#xff1a;1.比較的是左右子樹是否相同&#xff0c;不是節點的左右孩子&#xff1b; 2.左子樹左右中遍歷&#xff0c;右子樹右左中遍歷&#xff1b; 3.靈活遞歸。 /*** Definition for a binary tree node.* struct Tree…

【實驗室精選】PFA反應瓶帶鼓泡球 高效氣體鼓泡 化學分析優選

PFA反應瓶帶鼓泡球是一種特殊設計的實驗室容器&#xff0c;它集成了鼓泡球和PFA&#xff08;全氟烷氧基&#xff09;材料的反應瓶&#xff0c;用于氣體的鼓泡和液體的混合。以下是它的一些特點和用途&#xff1a; 特點&#xff1a; 鼓泡球設計&#xff1a;鼓泡球周圍布滿小孔&…

安裝realsenseSDK2.0

1、創造工作空間并進入 mkdir ros_ws cd ros_ws/ 2、克隆librealsense git clone https://github.com/IntelRealSense/librealsense cd librealsense 3、安裝依賴項 sudo apt-get install libssl-dev sudo apt-get install libusb-1.0-0-dev sudo apt-get install libudev…