Home » Android » A new way to manage USSD dialogs in android

A new way to manage USSD dialogs in android

Posted by: admin April 23, 2020 Leave a comment

Questions:

I’ve been reading threads about USSD dialogs in here and other forums for a few days. (by USSD I mean operator’s notifications with call cost details in it).

I’ve seen many solutions which apparently worked for lower API levels in android but after lots of tests, figured they don’t work anymore or at least I couldn’t get them to work.

First I wanted to know if there’s any way to detect if a ussd dialog has been shown to the user. so I tried this :
Prevent USSD dialog and read USSD response?

but all I could get from logs were somehow related to my app, although I could see them in Eclipse’s LogCat but no MMI related logs were captured in my app !
maybe it was working in lower Android versions than mine (4.2.2).

then I decided to use “IExtendedNetworkService” like it was used in the following links and many others :

https://github.com/alaasalman/ussdinterceptor

Using IExtendedNetworkService to get USSD response in Android

How to read USSD messages in android?

Implementing USSD features. Binding a service to the PhoneUtils without restarting the phone on every update

but it was also useless for android 4.2.2 and above.

then I found this link :
How to dismiss system dialog in Android?

it seemed promising but I couldn’t get it to work even after lots of tests.
I thought maybe I was doing something wrong or it was for lower APIs too.

after that I tried many other things like simulating home key and back key and even touching programmatically to hide that notification but none of them worked since they all work under my own activity.

Does anyone know if any of these methods or others work for managing or even detecting USSD messages in android 4.2.2 and above ?

I really appreciate any help,
thanks in advance.

How to&Answers:

It is possible using accessibility service.
First create a service class:

public class USSDService extends AccessibilityService {

public static String TAG = USSDService.class.getSimpleName();

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    Log.d(TAG, "onAccessibilityEvent");

    AccessibilityNodeInfo source = event.getSource();
    /* 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.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !String.valueOf(event.getClassName()).contains("AlertDialog")) {
        return;
    }
    if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && (source == null || !source.getClassName().equals("android.widget.TextView"))) {
        return;
    }
    if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && TextUtils.isEmpty(source.getText())) {
        return;
    }

    List<CharSequence> eventText;

    if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
        eventText = event.getText();
    } else {
        eventText = Collections.singletonList(source.getText());
    }

    String text = processUSSDText(eventText);

    if( TextUtils.isEmpty(text) ) return;

    // Close dialog
    performGlobalAction(GLOBAL_ACTION_BACK); // This works on 4.1+ only

    Log.d(TAG, text);
    // Handle USSD response here

}

private String processUSSDText(List<CharSequence> eventText) {
    for (CharSequence s : eventText) {
        String text = String.valueOf(s);
        // Return text if text is the expected ussd response
        if( true ) {
            return text;
        }
    }
    return null;
}

@Override
public void onInterrupt() {
}

@Override
protected void onServiceConnected() {
    super.onServiceConnected();
    Log.d(TAG, "onServiceConnected");
    AccessibilityServiceInfo info = new AccessibilityServiceInfo();
    info.flags = AccessibilityServiceInfo.DEFAULT;
    info.packageNames = new String[]{"com.android.phone"};
    info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
    info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
    setServiceInfo(info);
}
}

Declare it in Android manifest

<service android:name=".USSDService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
    <action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
    android:resource="@xml/ussd_service" />

Create a xml file that describes the accessibility service called ussd_service

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:notificationTimeout="0"
android:packageNames="com.android.phone" />

That’s it. Once app is installed, you have to enable the service in Accessibility Settings (Setting->Accessibility Setting -> YourAppName).

Solution described here and here (russian).

Answer:

Unfortunately no way.

We’ve been searching for that command is also a solution to this problem, but if it turned out to get information only through the parsing of logs in the phone that does not guarantee 100% of the work on all devices.

As a result, we were able to reach an agreement with mobile operators in our country (we only have 3 mobile operator), and they provided us with the API to obtain the balance of the phone number, but this method only works locally.