123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- /*
- * Copyright (c) 2020. BoostTag E.I.R.L. Romell D.Z.
- * All rights reserved
- * porfile.romellfudi.com
- */
- package com.romellfudi.ussdlibrary;
- import android.accessibilityservice.AccessibilityService;
- import android.content.ClipData;
- import android.content.ClipboardManager;
- import android.content.Context;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Parcel;
- import android.util.Log;
- import android.view.accessibility.AccessibilityEvent;
- import android.view.accessibility.AccessibilityNodeInfo;
- import com.elvishew.xlog.XLog;
- import com.google.gson.Gson;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * AccessibilityService for ussd windows on Android mobile Telcom
- *
- * @author Romell Dominguez
- * @version 1.1.c 27/09/2018
- * @since 1.0.a
- */
- public class USSDService extends AccessibilityService {
- private static String TAG = "USSDServiceUSSD";
- public static AccessibilityEvent event;
- @Override
- public void onAccessibilityEvent(AccessibilityEvent event) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- this.event = new AccessibilityEvent(event);
- } else {
- Parcel parcel = Parcel.obtain();
- event.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AccessibilityEvent newEvent = AccessibilityEvent.CREATOR.createFromParcel(parcel);
- parcel.recycle();
- this.event = newEvent;
- }
- XLog.i("USSDService Event Json : " + getEventNowRootInActiveWindow(event));
- XLog.i(String.format("USSDService onAccessibilityEvent: [type] %s [class] %s [package] %s [time] %s [text] %s" +
- " [ContentChangeTypes] %s [WindowChanges] %s",
- event.getEventType(), event.getClassName(), event.getPackageName(),
- event.getEventTime(), event.getText(), event.getContentChangeTypes(),event.getWindowChanges()));
- if (USSDController.instance == null || !USSDController.instance.isRunning) {
- XLog.e("USSDService Error : USSDController.instance = " + (USSDController.instance == null));
- if (USSDController.instance != null) {
- XLog.e("USSDService Error : USSDController.instance.isRunning = " + (USSDController.instance.isRunning));
- }
- return;
- }
- String response = event.getText().toString();
- if (LoginView(event) && notInputText(event)) {
- XLog.i("USSDService: 1");
- clickOnButton(event, 0);
- USSDController.instance.isRunning = false;
- if (USSDController.instance.send)
- USSDController.instance.callbackMessage.over(response);
- else
- USSDController.instance.callbackInvoke.over(response);
- } else if (problemView(event) || LoginView(event)) {
- XLog.i("USSDService: 2");
- clickOnButton(event, 1);
- if (USSDController.instance.send)
- USSDController.instance.callbackMessage.over(response);
- else
- USSDController.instance.callbackInvoke.over(response);
- } else if (isUSSDWidget(event)) {
- XLog.i("USSDService: 3");
- if (notInputText(event)) {
- XLog.i("USSDService: 4");
- clickOnButton(event, 0);
- USSDController.instance.isRunning = false;
- if (USSDController.instance.send)
- USSDController.instance.callbackMessage.over(response);
- else
- USSDController.instance.callbackInvoke.over(response);
- } else {
- XLog.i("USSDService: 5");
- if (USSDController.instance.send)
- USSDController.instance.callbackMessage.responseMessage(response);
- else
- USSDController.instance.callbackInvoke.responseInvoke(response);
- }
- } else {
- XLog.e("USSDService Error : 未走进任何逻辑循环");
- }
- }
- /**
- * Send whatever you want via USSD
- *
- * @param text any string
- */
- public static void send(String text) {
- setTextIntoField(event, text);
- clickOnButton(event, 1);
- }
- /**
- * Cancel USSD
- */
- public static void cancel() {
- clickOnButton(event, 0);
- }
- /**
- * set text into input text at USSD widget
- *
- * @param event AccessibilityEvent
- * @param data Any String
- */
- private static void setTextIntoField(AccessibilityEvent event, String data) {
- USSDController ussdController = USSDController.instance;
- Bundle arguments = new Bundle();
- arguments.putCharSequence(
- AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, data);
- for (AccessibilityNodeInfo leaf : getLeaves(event)) {
- if (leaf.getClassName().equals("android.widget.EditText")
- && !leaf.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)) {
- ClipboardManager clipboardManager = ((ClipboardManager) ussdController.context
- .getSystemService(Context.CLIPBOARD_SERVICE));
- if (clipboardManager != null) {
- clipboardManager.setPrimaryClip(ClipData.newPlainText("text", data));
- }
- leaf.performAction(AccessibilityNodeInfo.ACTION_PASTE);
- }
- }
- }
- /**
- * Method evaluate if USSD widget has input text
- *
- * @param event AccessibilityEvent
- * @return boolean has or not input text
- */
- protected static boolean notInputText(AccessibilityEvent event) {
- boolean flag = true;
- for (AccessibilityNodeInfo leaf : getLeaves(event)) {
- if (leaf.getClassName().equals("android.widget.EditText")) flag = false;
- }
- return flag;
- }
- /**
- * The AccessibilityEvent is instance of USSD Widget class
- *
- * @param event AccessibilityEvent
- * @return boolean AccessibilityEvent is USSD
- */
- private boolean isUSSDWidget(AccessibilityEvent event) {
- return (event.getClassName().equals("amigo.app.AmigoAlertDialog")
- || event.getClassName().equals("android.app.AlertDialog")
- || event.getClassName().equals("com.android.phone.oppo.settings.LocalAlertDialog")
- || event.getClassName().equals("com.zte.mifavor.widget.AlertDialog")
- || event.getClassName().equals("color.support.v7.app.AlertDialog")
- || event.getClassName().equals("com.transsion.widgetslib.dialog.PromptDialog")
- || event.getClassName().equals("miuix.appcompat.app.AlertDialog")
- || event.getClassName().equals("androidx.appcompat.app.AlertDialog"));
- }
- /**
- * The View has a login message into USSD Widget
- *
- * @param event AccessibilityEvent
- * @return boolean USSD Widget has login message
- */
- private boolean LoginView(AccessibilityEvent event) {
- return isUSSDWidget(event)
- && USSDController.instance.map.get(USSDController.KEY_LOGIN)
- .contains(event.getText().get(0).toString());
- }
- /**
- * The View has a problem message into USSD Widget
- *
- * @param event AccessibilityEvent
- * @return boolean USSD Widget has problem message
- */
- protected boolean problemView(AccessibilityEvent event) {
- return isUSSDWidget(event)
- && USSDController.instance.map.get(USSDController.KEY_ERROR)
- .contains(event.getText().get(0).toString());
- }
- /**
- * click a button using the index
- *
- * @param event AccessibilityEvent
- * @param index button's index
- */
- protected static void clickOnButton(AccessibilityEvent event, int index) {
- int count = -1;
- for (AccessibilityNodeInfo leaf : getLeaves(event)) {
- if (leaf.getClassName().toString().toLowerCase().contains("button")) {
- count++;
- if (count == index) {
- leaf.performAction(AccessibilityNodeInfo.ACTION_CLICK);
- }
- }
- }
- }
- private static List<AccessibilityNodeInfo> getLeaves(AccessibilityEvent event) {
- List<AccessibilityNodeInfo> leaves = new ArrayList<>();
- if (event.getSource() != null) {
- getLeaves(leaves, event.getSource());
- }
- return leaves;
- }
- private static void getLeaves(List<AccessibilityNodeInfo> leaves, AccessibilityNodeInfo node) {
- if (node.getChildCount() == 0) {
- leaves.add(node);
- return;
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- getLeaves(leaves, node.getChild(i));
- }
- }
- /**
- * Active when SO interrupt the application
- */
- @Override
- public void onInterrupt() {
- Log.d(TAG, "onInterrupt");
- }
- /**
- * Configure accessibility server from Android Operative System
- */
- @Override
- protected void onServiceConnected() {
- super.onServiceConnected();
- Log.d(TAG, "onServiceConnected");
- }
- public static String getEventNowRootInActiveWindow(AccessibilityEvent event) {
- String PageJson = "{}";
- AccessibilityNodeInfo node = event.getSource();
- if (node != null) {
- NodeInfoWrapper nodeInfoWrapper = traverseNode(node);
- Gson gson = new Gson();
- PageJson = gson.toJson(nodeInfoWrapper);
- }
- return PageJson;
- }
- private static class NodeInfoWrapper {
- public String txt;
- public String vId;
- public String cName;
- public String pName;
- public int hashcode;
- public int childCount;
- //用于判断节点是否可以打开弹出窗口(popup)canOpenPopup()方法用于判断给定的节点是否具有打开弹出窗口的能力
- public boolean canOpenPopup;
- //判断节点是否对用户可见
- public boolean visibleToUser;
- //判断节点是否启用
- public boolean isEnabled;
- public String hintText;
- //判断节点是否可点击
- public boolean isClickable;
- //判断节点是否可长按
- public boolean isLongClickable;
- //判断节点是否可编辑
- public boolean isEditable;
- //判断节点是否可选择
- public boolean isCheckable;
- //判断节点的选择状态
- public boolean isChecked;
- //判断节点是否具有焦点
- public boolean focused;
- //判断节点是否可滚动
- public boolean scrollable;
- public boolean isSelected;
- public boolean isAccessibilityFocused;
- public boolean isContentInvalid;
- public boolean isContextClickable;
- public boolean isDismissable;
- public boolean isFocusable;
- public boolean isFocused;
- public boolean isHeading;
- public boolean isImportantForAccessibility;
- public boolean isMultiLine;
- public boolean isPassword;
- public boolean isScreenReaderFocusable;
- public boolean isScrollable;
- public boolean isShowingHintText;
- public boolean isTextEntryKey;
- public boolean isTextSelectable;
- public boolean isVisibleToUser;
- public List<NodeInfoWrapper> childNodes;
- }
- private static NodeInfoWrapper traverseNode(AccessibilityNodeInfo nodeInfo) {
- NodeInfoWrapper nodeInfoWrapper = new NodeInfoWrapper();
- nodeInfoWrapper.txt = nodeInfo.getText() != null ? nodeInfo.getText().toString() : "";
- nodeInfoWrapper.vId = nodeInfo.getViewIdResourceName();
- nodeInfoWrapper.cName = nodeInfo.getClassName().toString();
- nodeInfoWrapper.pName = nodeInfo.getPackageName().toString();
- nodeInfoWrapper.hashcode = nodeInfo.hashCode();
- nodeInfoWrapper.childCount = nodeInfo.getChildCount();
- nodeInfoWrapper.canOpenPopup = nodeInfo.canOpenPopup();
- nodeInfoWrapper.visibleToUser = nodeInfo.isVisibleToUser();
- nodeInfoWrapper.isEnabled = nodeInfo.isEnabled();
- nodeInfoWrapper.hintText = nodeInfo.getHintText() != null ? nodeInfo.getText().toString() : "";
- nodeInfoWrapper.isClickable = nodeInfo.isClickable();
- nodeInfoWrapper.isLongClickable = nodeInfo.isLongClickable();
- nodeInfoWrapper.isEditable = nodeInfo.isEditable();
- nodeInfoWrapper.isCheckable = nodeInfo.isCheckable();
- nodeInfoWrapper.isChecked = nodeInfo.isChecked();
- nodeInfoWrapper.focused = nodeInfo.isFocused();
- nodeInfoWrapper.scrollable = nodeInfo.isScrollable();
- nodeInfoWrapper.isSelected = nodeInfo.isSelected();
- nodeInfoWrapper.isAccessibilityFocused = nodeInfo.isAccessibilityFocused();
- nodeInfoWrapper.isContentInvalid = nodeInfo.isContentInvalid();
- nodeInfoWrapper.isContextClickable = nodeInfo.isContextClickable();
- nodeInfoWrapper.isDismissable = nodeInfo.isDismissable();
- nodeInfoWrapper.isFocusable = nodeInfo.isFocusable();
- nodeInfoWrapper.isFocused = nodeInfo.isFocused();
- nodeInfoWrapper.isHeading = nodeInfo.isHeading();
- nodeInfoWrapper.isImportantForAccessibility = nodeInfo.isImportantForAccessibility();
- nodeInfoWrapper.isMultiLine = nodeInfo.isMultiLine();
- nodeInfoWrapper.isPassword = nodeInfo.isPassword();
- nodeInfoWrapper.isScreenReaderFocusable = nodeInfo.isScreenReaderFocusable();
- nodeInfoWrapper.isScrollable = nodeInfo.isScrollable();
- nodeInfoWrapper.isShowingHintText = nodeInfo.isShowingHintText();
- nodeInfoWrapper.isTextEntryKey = nodeInfo.isTextEntryKey();
- nodeInfoWrapper.isVisibleToUser = nodeInfo.isVisibleToUser();
- List<NodeInfoWrapper> childNodes = new ArrayList<>();
- for (int i = 0; i < nodeInfo.getChildCount(); i++) {
- AccessibilityNodeInfo childNode = nodeInfo.getChild(i);
- if (childNode != null) {
- NodeInfoWrapper childNodeWrapper = traverseNode(childNode);
- childNodes.add(childNodeWrapper);
- }
- }
- nodeInfoWrapper.childNodes = childNodes;
- return nodeInfoWrapper;
- }
- }
|