Halo Great People
By using an Accessibility Service class I am able to successfully run as USSD session e.g. *796#.
I have the service listening to USSD responses, so after dialing a code from my main activity, the service listens to responses, interrupts the dialog, inputs a text the replies back.
I am doing this to automate services like checking Airtime balance, subscribing to services...e.t.c
however, I would like to hide the session running from the user, I thought by using the draw over other apps function, so that what the user sees is a layout file displaying, 'Processing Request...'
If I run it without displaying the layout over other apps, it works perfectly! But, when I call the app to display the layout file, the app seems to not to interact to the USSD responses I get. I wanted to achieve something like what the Hover SDK does.
Is there a way to handle the USSD running in the background?
Sorry for a lengthy explanation, hope it describes well. Any help is greatly APPRECIATED. Let me know if any clarification is needed.
Here is the service class the handles the ussd responses;
class USSDService : AccessibilityService() {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onAccessibilityEvent(event: AccessibilityEvent) {
try {
val source = event.source
/* if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !event.getClassName().equals("android.app.AlertDialog")) { // android.app.AlertDialog is the standard but not for all phones */
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !event.className.toString()
.contains("AlertDialog")
) {
return
}
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && (source == null || source.className != "android.widget.TextView")) {
return
}
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && TextUtils.isEmpty(
source!!.text
)
) {
return
}
val eventText: List<CharSequence> = if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
event.text
} else {
Collections.singletonList(source!!.text)
}
val text = processUSSDText(eventText).toString()
if (TextUtils.isEmpty(text)) return
val intent = Intent("com.times.ussd.action.REFRESH")
intent.putExtra("message", text)
val list: List<AccessibilityNodeInfo> = nodeInfo.findAccessibilityNodeInfosByText("Send")
for (node in list) {
if (text.contains("Account Services")) {
performGlobalAction(GLOBAL_ACTION_BACK)
/** Initiate Draw Over Apps */
val nodeInput: AccessibilityNodeInfo = nodeInfo.findFocus(AccessibilityNodeInfo.FOCUS_INPUT)
val bundle = Bundle()
bundle.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "1")
nodeInput.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, bundle)
nodeInput.refresh()
Handler().postDelayed({ node.performAction(AccessibilityNodeInfo.ACTION_CLICK) }, 1)
} else {
if (text.contains("Check balance")) {
performGlobalAction(GLOBAL_ACTION_BACK)
val nodeInput: AccessibilityNodeInfo = nodeInfo.findFocus(AccessibilityNodeInfo.FOCUS_INPUT)
val bundle = Bundle()
bundle.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "5")
nodeInput.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, bundle)
nodeInput.refresh()
Handler().postDelayed({ node.performAction(AccessibilityNodeInfo.ACTION_CLICK) }, 1)
}
}
}
} catch (e: Exception) {
val toast = Toast.makeText(this, "ERROR!!
$e", Toast.LENGTH_LONG).show()
}
}
}
Here is code to call the ussd code;
val intent = Intent(Intent.ACTION_CALL).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.data = Uri.parse("tel:*796%23")
intent.putExtra("com.android.phone.force.slot", true)
intent.putExtra("com.android.phone.extra.slot", safaricomSim)
if (phoneAccountHandleList != null && phoneAccountHandleList.size > safaricomSim) intent.putExtra(
"android.telecom.extra.PHONE_ACCOUNT_HANDLE",
phoneAccountHandleList[safaricomSim]
)
startActivity(intent)
after calling this, I would to handle the UDDS interaction in the background, PLEASE, HELP. Thanks in advance.
See Question&Answers more detail:
os