Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
479 views
in Technique[技术] by (71.8m points)

android - I there a way to run an interactive USSD session and hide the session behind a layout file

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

My team and I have been working on a service called AutoUssd (https://autoussd.com) which you can use to accomplish this.

The SDK allows you to create multi-step USSD sessions which are hidden behind a layout file and the results of a session is reported to your app via a callback.

Kindly check it out to see if it fits your needs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...