USSDService.java 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Copyright (c) 2020. BoostTag E.I.R.L. Romell D.Z.
  3. * All rights reserved
  4. * porfile.romellfudi.com
  5. */
  6. package com.romellfudi.ussdlibrary;
  7. import android.accessibilityservice.AccessibilityService;
  8. import android.content.ClipData;
  9. import android.content.ClipboardManager;
  10. import android.content.Context;
  11. import android.os.Build;
  12. import android.os.Bundle;
  13. import android.util.Log;
  14. import android.view.accessibility.AccessibilityEvent;
  15. import android.view.accessibility.AccessibilityNodeInfo;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. /**
  19. * AccessibilityService for ussd windows on Android mobile Telcom
  20. *
  21. * @author Romell Dominguez
  22. * @version 1.1.c 27/09/2018
  23. * @since 1.0.a
  24. */
  25. public class USSDService extends AccessibilityService {
  26. private static String TAG = "USSDServiceUSSD";
  27. public static AccessibilityEvent event;
  28. @Override
  29. public void onAccessibilityEvent(AccessibilityEvent event) {
  30. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
  31. this.event = new AccessibilityEvent(event);
  32. } else {
  33. this.event = event;
  34. }
  35. if (USSDController.instance == null || !USSDController.instance.isRunning) {
  36. return;
  37. }
  38. String response = event.getText().toString();
  39. if (LoginView(event) && notInputText(event)) {
  40. // first view or logView, do nothing, pass / FIRST MESSAGE
  41. clickOnButton(event, 0);
  42. USSDController.instance.isRunning = false;
  43. if (USSDController.instance.send)
  44. USSDController.instance.callbackMessage.over(response);
  45. else
  46. USSDController.instance.callbackInvoke.over(response);
  47. } else if (problemView(event) || LoginView(event)) {
  48. // deal down
  49. clickOnButton(event, 1);
  50. if (USSDController.instance.send)
  51. USSDController.instance.callbackMessage.over(response);
  52. else
  53. USSDController.instance.callbackInvoke.over(response);
  54. } else if (isUSSDWidget(event)) {
  55. // ready for work
  56. // if (response.contains("\n")) {
  57. // response = response.substring(response.indexOf('\n') + 1);
  58. // }
  59. if (notInputText(event)) {
  60. // not more input panels / LAST MESSAGE
  61. // sent 'OK' button
  62. clickOnButton(event, 0);
  63. USSDController.instance.isRunning = false;
  64. if (USSDController.instance.send)
  65. USSDController.instance.callbackMessage.over(response);
  66. else
  67. USSDController.instance.callbackInvoke.over(response);
  68. } else {
  69. // sent option 1
  70. // USSDController.instance.callbackInvoke = null;
  71. // USSDController.instance.callbackMessage = null;
  72. if (USSDController.instance.send)
  73. USSDController.instance.callbackMessage.responseMessage(response);
  74. else
  75. USSDController.instance.callbackInvoke.responseInvoke(response);
  76. }
  77. }
  78. }
  79. /**
  80. * Send whatever you want via USSD
  81. *
  82. * @param text any string
  83. */
  84. public static void send(String text) {
  85. setTextIntoField(event, text);
  86. clickOnButton(event, 1);
  87. }
  88. /**
  89. * Cancel USSD
  90. */
  91. public static void cancel() {
  92. clickOnButton(event, 0);
  93. }
  94. /**
  95. * set text into input text at USSD widget
  96. *
  97. * @param event AccessibilityEvent
  98. * @param data Any String
  99. */
  100. private static void setTextIntoField(AccessibilityEvent event, String data) {
  101. USSDController ussdController = USSDController.instance;
  102. Bundle arguments = new Bundle();
  103. arguments.putCharSequence(
  104. AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, data);
  105. for (AccessibilityNodeInfo leaf : getLeaves(event)) {
  106. if (leaf.getClassName().equals("android.widget.EditText")
  107. && !leaf.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)) {
  108. ClipboardManager clipboardManager = ((ClipboardManager) ussdController.context
  109. .getSystemService(Context.CLIPBOARD_SERVICE));
  110. if (clipboardManager != null) {
  111. clipboardManager.setPrimaryClip(ClipData.newPlainText("text", data));
  112. }
  113. leaf.performAction(AccessibilityNodeInfo.ACTION_PASTE);
  114. }
  115. }
  116. }
  117. /**
  118. * Method evaluate if USSD widget has input text
  119. *
  120. * @param event AccessibilityEvent
  121. * @return boolean has or not input text
  122. */
  123. protected static boolean notInputText(AccessibilityEvent event) {
  124. boolean flag = true;
  125. for (AccessibilityNodeInfo leaf : getLeaves(event)) {
  126. if (leaf.getClassName().equals("android.widget.EditText")) flag = false;
  127. }
  128. return flag;
  129. }
  130. /**
  131. * The AccessibilityEvent is instance of USSD Widget class
  132. *
  133. * @param event AccessibilityEvent
  134. * @return boolean AccessibilityEvent is USSD
  135. */
  136. private boolean isUSSDWidget(AccessibilityEvent event) {
  137. return (event.getClassName().equals("amigo.app.AmigoAlertDialog")
  138. || event.getClassName().equals("android.app.AlertDialog")
  139. || event.getClassName().equals("com.android.phone.oppo.settings.LocalAlertDialog")
  140. || event.getClassName().equals("com.zte.mifavor.widget.AlertDialog")
  141. || event.getClassName().equals("color.support.v7.app.AlertDialog")
  142. || event.getClassName().equals("com.transsion.widgetslib.dialog.PromptDialog")
  143. || event.getClassName().equals("miuix.appcompat.app.AlertDialog"));
  144. }
  145. /**
  146. * The View has a login message into USSD Widget
  147. *
  148. * @param event AccessibilityEvent
  149. * @return boolean USSD Widget has login message
  150. */
  151. private boolean LoginView(AccessibilityEvent event) {
  152. return isUSSDWidget(event)
  153. && USSDController.instance.map.get(USSDController.KEY_LOGIN)
  154. .contains(event.getText().get(0).toString());
  155. }
  156. /**
  157. * The View has a problem message into USSD Widget
  158. *
  159. * @param event AccessibilityEvent
  160. * @return boolean USSD Widget has problem message
  161. */
  162. protected boolean problemView(AccessibilityEvent event) {
  163. return isUSSDWidget(event)
  164. && USSDController.instance.map.get(USSDController.KEY_ERROR)
  165. .contains(event.getText().get(0).toString());
  166. }
  167. /**
  168. * click a button using the index
  169. *
  170. * @param event AccessibilityEvent
  171. * @param index button's index
  172. */
  173. protected static void clickOnButton(AccessibilityEvent event, int index) {
  174. int count = -1;
  175. for (AccessibilityNodeInfo leaf : getLeaves(event)) {
  176. if (leaf.getClassName().toString().toLowerCase().contains("button")) {
  177. count++;
  178. if (count == index) {
  179. leaf.performAction(AccessibilityNodeInfo.ACTION_CLICK);
  180. }
  181. }
  182. }
  183. }
  184. private static List<AccessibilityNodeInfo> getLeaves(AccessibilityEvent event) {
  185. List<AccessibilityNodeInfo> leaves = new ArrayList<>();
  186. if (event.getSource() != null) {
  187. getLeaves(leaves, event.getSource());
  188. }
  189. return leaves;
  190. }
  191. private static void getLeaves(List<AccessibilityNodeInfo> leaves, AccessibilityNodeInfo node) {
  192. if (node.getChildCount() == 0) {
  193. leaves.add(node);
  194. return;
  195. }
  196. for (int i = 0; i < node.getChildCount(); i++) {
  197. getLeaves(leaves, node.getChild(i));
  198. }
  199. }
  200. /**
  201. * Active when SO interrupt the application
  202. */
  203. @Override
  204. public void onInterrupt() {
  205. Log.d(TAG, "onInterrupt");
  206. }
  207. /**
  208. * Configure accessibility server from Android Operative System
  209. */
  210. @Override
  211. protected void onServiceConnected() {
  212. super.onServiceConnected();
  213. Log.d(TAG, "onServiceConnected");
  214. }
  215. }