I am trying to make accessibility services class for the following tasks in my app:
- Sending request (eg. *121#)
- Read response
- Find a string inside the response
- There will be a number before the string. Extract it
- respond with the extracted number
This is my code so far
public class AccServices extends AccessibilityService {
private static final String TAG = "AccServices";
private static String ussdCode;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && "com.example.testingaccessibility.ACTION_SEND_USSD".equals(intent.getAction())) {
ussdCode = intent.getStringExtra("ussd_code");
Log.d(TAG, "Received USSD Code: " + ussdCode);
// Start USSD dialer
if (ussdCode != null) {
String ussdDialCode = ussdCode.replace("#", Uri.encode("#"));
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + ussdDialCode));
callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(callIntent);
}
}
return START_NOT_STICKY;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent");
if (event.getClassName() != null && event.getClassName().equals("android.app.AlertDialog")) {
List<CharSequence> eventText = event.getText();
if (eventText != null && eventText.size() > 0) {
StringBuilder ussdMessage = new StringBuilder();
for (CharSequence text : eventText) {
ussdMessage.append(text);
}
Log.d(TAG, "USSD Message: " + ussdMessage.toString());
Intent intent = new Intent("com.example.testingaccessibility.ACTION_USSD_RECEIVED");
intent.putExtra("ussd_message", ussdMessage.toString());
sendBroadcast(intent);
// Find the number before "GP STAR"
String response = ussdMessage.toString();
String numberBeforeGpStar = extractNumberBeforeGpStar(response);
if (numberBeforeGpStar != null) {
respondToUssd(numberBeforeGpStar);
}
performGlobalAction(GLOBAL_ACTION_BACK);
}
}
}
private String extractNumberBeforeGpStar(String response) {
Pattern pattern = Pattern.compile("(\d+)\s+GP STAR");
Matcher matcher = pattern.matcher(response);
if (matcher.find()) {
String numberBeforeGpStar = matcher.group(1);
// Show a Toast message with the number before "GP STAR"
Toast.makeText(this, "Number before GP STAR: " + numberBeforeGpStar, Toast.LENGTH_LONG).show();
return numberBeforeGpStar;
}
return null;
}
private void respondToUssd(String response) {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
if (rootNode != null) {
List<AccessibilityNodeInfo> inputNodes = rootNode.findAccessibilityNodeInfosByViewId("com.android.phone:id/inputField"); // Replace with actual input field ID
if (inputNodes != null && !inputNodes.isEmpty()) {
AccessibilityNodeInfo inputNode = inputNodes.get(0);
Bundle args = new Bundle();
args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, response);
inputNode.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
// Find and click the send button
List<AccessibilityNodeInfo> sendNodes = rootNode.findAccessibilityNodeInfosByViewId("com.android.phone:id/sendButton"); // Replace with actual send button ID
if (sendNodes != null && !sendNodes.isEmpty()) {
AccessibilityNodeInfo sendNode = sendNodes.get(0);
sendNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
rootNode.recycle();
}
}
@Override
public void onInterrupt() {
Log.d(TAG, "Accessibility service interrupted");
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.d(TAG, "Accessibility service connected");
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.packageNames = new String[]{"com.android.phone"};
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.notificationTimeout = 0;
setServiceInfo(info);
}
}
So far, the code is working up to step 4, but I cannot respond because after the USSD request is sent (step 1), the USSD menu/response dialog box appears on the screen. I need to suppress it and keep it in the background so that I can send a response to it. This is the first issue.
The second issue is that I need to find the actual input field ID and the actual send button ID of the USSD dialogue box in order to interact with it. However, I don’t know how to do this. I am desperate for a solution, so any help would be highly appreciated.