Prevent USSD dialog and read USSD response?

39,351

Solution 1

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" />
 </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).

Solution 2

It works in Android 2.3, but i'm not completely sure if this can work in a superior version, follow the instructions:

  1. Connect your phone USB to your computer (Debug Mode)
  2. Type adb devices (your phone must be listing)
  3. Type adb shell
  4. Type logcat -v time -b main PhoneUtils:D > output.txt
  5. Now in your phone, send a ussd code example: #123# wait a moment and then in your console press Ctrl + C
  6. Read the output.txt and find this word displayMMIComplete
Share:
39,351

Related videos on Youtube

Jack
Author by

Jack

Updated on July 09, 2022

Comments

  • Jack
    Jack almost 2 years

    i did many research about ussd but I can't read USSD respone and how can I prevent ussd dialog like this application.

    https://play.google.com/store/apps/details?id=com.iba.ussdchecker&hl=en

    i install this https://github.com/alaasalman/ussdinterceptor restart my phone (S2 android 4.0.3), send ussd code but nothing happen, someone tell me that I have to read the log, but how can i do that.

    i try these code to read USSD from log

    USSD.java

        package com.example.ussd;
    
        import java.io.BufferedReader;
        import java.io.IOException;
        import java.io.InputStreamReader;
        import java.util.Calendar;
        import java.util.Date;
        import java.text.ParseException;
        import java.text.SimpleDateFormat;
    
        import android.util.Log;
    
        public class USSD {
    
            private static String startmsg = "displayMMIComplete"; // start msg to look
                                                                    // for
            private static String endmsg = "MMI code has finished running"; // stop msg
            private static String trimmsg = "- using text from MMI message: '"; // a msg
                                                                                // to
                                                                                // remove
                                                                                // from
                                                                                // the
                                                                                // text
    
            private long before = 3000; // delay (ms) before creation of the class
                                        // before a msg (USDD) is valid (use timestamp)
            private long after = 3000; // delay (ms) after creation of the class that a
                                        // msg (USDD) is valid (wait after ms)
    
            private String msg = ""; // the USSD message
            private boolean found = false;
            private long t = -1; // timestamp of the found log
    
            public USSD() {
                this(3000, 3000);
            }
    
            // USSD in log : example
            public USSD(long before_creation, long after_creation) {
                before = before_creation;
                after = after_creation;
                long timestamp = System.currentTimeMillis(); // creation of the class
                                                                // --> look for the USSD
                                                                // msg in the logs
                Log.d("USSDClass",
                        "Class creation - timestamp: " + String.valueOf(timestamp));
                try {
                    // sample code taken from alogcat ...
                    Process logcatProc = Runtime.getRuntime().exec(
                            "logcat -v time -b main PhoneUtils:D"); // get PhoneUtils
                                                                    // debug log with
                                                                    // time information
                    BufferedReader mReader = new BufferedReader(new InputStreamReader(
                            logcatProc.getInputStream()), 1024);
                    String line = "";
                    boolean tostop = false;
                    long stop = timestamp + after; // to stop the while after "after" ms
                    while (((line = mReader.readLine()) != null)
                            && (System.currentTimeMillis() < stop) && (tostop == false)) {
                        if (line.length() > 19) // the line should be at least with a
                                                // length of a timestamp (19) !
                        {
                            if (line.contains(startmsg)) // check if it is a USSD msg
                            {
                                // log example :
                                // "12-10 20:36:39.321 D/PhoneUtils(  178): displayMMIComplete: state=COMPLETE"
                                t = extracttimestamp(line); // extract the timestamp of
                                                            // thie msg
                                Log.d("USSDClass", "Found line at timestamp : "
                                        + String.valueOf(t));
                                if (t >= timestamp - before)
                                    found = true; // start of an USDD is found & is
                                                    // recent !
                            } else if (found) {
                                // log example :
                                // "12-10 20:36:39.321 D/PhoneUtils(  178): displayMMIComplete: state=COMPLETE"
                                if (line.contains(endmsg))
                                    tostop = true;
                                else {
                                    // log example :
                                    // "12-10 20:36:39.321 D/PhoneUtils(  178): - using text from MMI message: 'Your USSD message with one or several lines"
                                    Log.d("USSDClass", "Line content : " + line);
                                    String[] v = line.split("\\): "); // doesn't need
                                                                        // log
                                                                        // information
                                                                        // --> split
                                                                        // with "): "
                                                                        // separator
                                    if (v.length > 1)
                                        msg += v[1].replace(trimmsg, "").trim() + "\n";
    
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    Log.d("USSDClass", "Exception:" + e.toString());
                }
            }
    
            public boolean IsFound() {
                return found;
            }
    
            public String getMsg() {
                return msg;
            }
    
            // extract timestamp from a log line with format
            // "MM-dd HH:mm:ss.ms Level/App:msg" Example : 12-10 20:36:39.321
            // Note : known bug : happy new year check will not work !!!
            private long extracttimestamp(String line) {
                long timestamp = -1; // default value if no timestamp is found
                String[] v = line.split(" ");
                if (v.length > 1) // check if there is space
                {
                    Calendar C = Calendar.getInstance();
                    int y = C.get(Calendar.YEAR);
                    String txt = v[0] + "-" + y + " " + v[1]; // transform in format
                                                                // "MM-dd-yyyy HH:mm:ss"
                    SimpleDateFormat formatter = new SimpleDateFormat(
                            "MM-dd-yyyy HH:mm:ss");
                    try {
                        Date tmp = formatter.parse(txt);
                        timestamp = tmp.getTime();
                        String[] ms = v[1].split("."); // get ms
                        if (ms.length > 1)
                            timestamp += Integer.getInteger(ms[1]);
    
                    } catch (ParseException e) {
                        Log.d("USSDClass",
                                "USDD.extractimestamp exception:" + e.toString());
                    }
                }
                return timestamp;
    
            }
    
        }
    

    UssdActivity.java

    package com.example.ussd;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.AutoCompleteTextView;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class UssdActivity extends Activity implements OnClickListener {
        /** Called when the activity is first created. */
        private TextView view;
        private AutoCompleteTextView number;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            Button button = (Button) findViewById(R.id.button1);
            button.setOnClickListener(this);
            this.view = (TextView) findViewById(R.id.Text2);
            this.number = (AutoCompleteTextView) findViewById(R.id.Text1);
        }
    
        @Override
        public void onClick(View arg0) {
            String encodedHash = Uri.encode("#");
            call("*" + number.getText() + encodedHash);
            this.view.setText("");
        }
    
        protected void call(String phoneNumber) {
            try {
                startActivityForResult(
                        new Intent("android.intent.action.CALL", Uri.parse("tel:"
                                + phoneNumber)), 1);
            } catch (Exception eExcept) {
                this.view.append("\n\n " + "\n" + eExcept.toString());
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            USSD ussd = new USSD(4000, 4000);
            if (ussd.IsFound())
                this.view.append("\n test" + ussd.getMsg());
            else
                this.view.append("" + R.string.error_ussd_msg);
        }
    
    }
    

    and output is something like this:

    com.sec.android.app.callsetting.allcalls:com.sec.android.callsetting.allcalls.AllCallsProvider Terminated ALSA PLAYBACK device hifi
    
    • Wilson
      Wilson almost 10 years
      Have you got the solution ?
    • Jack
      Jack almost 10 years
      not yet, does you have any idea for this problem?
    • Wilson
      Wilson almost 10 years
      No i am just trying and working around but no +ve progress.
    • Jack
      Jack almost 10 years
      please response in this topic whenever you found solution :)
    • Wilson
      Wilson almost 10 years
      Ya sure I'll do Jack.
    • hamidfzm
      hamidfzm over 9 years
    • Jack
      Jack over 9 years
      @HamidFzM in android > 4.2, we make USSD dial like this
    • Gh0sT
      Gh0sT over 9 years
      Check out the answer here stackoverflow.com/questions/6515906/…
    • Harry Sharma
      Harry Sharma over 8 years
      Have you find the solution..??
  • Umesh Isran
    Umesh Isran over 8 years
    This works perfect on lollipop, but no success on 4.2.2 and 4.0.3.?
  • Umesh Isran
    Umesh Isran over 8 years
    I gues this problem is device specific. The above code works for Samsung Duos(4.0.4), One plus one(5.1.1), Xiomi mi(4.4), but fails to work on Micromax A177(4.2.2), Micromax A905(4.0.4), Lenovo (4.2.2). Please if you can check the same and look for a solution..
  • HenBoy331
    HenBoy331 over 8 years
    Yes on some devices it does not work. On some devices it is com.android.phone.UssdAlertActivity instead of android.app.AlertDialog
  • HenBoy331
    HenBoy331 over 8 years
    Please check my new answer. I made it work from my side. Please check!
  • HenBoy331
    HenBoy331 over 8 years
    Vote up if I helped ;)
  • Umesh Isran
    Umesh Isran over 8 years
    @henboy - Did u find a solution to make this work on all devices.?
  • Umesh Isran
    Umesh Isran over 8 years
    @henboy - the above code is not working for me:( Plz if u can u pass me the code at [email protected]
  • HenBoy331
    HenBoy331 over 8 years
    I met also some case where it does not work. I manage to make it work on those phones(Htc One, Htc One X). Please try my updated answer.
  • Umesh Isran
    Umesh Isran over 8 years
    @henboy : I tried your updated answer, still no luck. event.getText() returns "Phone" as value for micromax and lenovo device..
  • Avanish Singh
    Avanish Singh about 8 years
    Hey guys.. i am not geting text of AlertDialog box using event.getText(). i got "PHONE" text.. help any one ..
  • Alex
    Alex over 7 years
    On all devices / Android versions or is there any limitation ?
  • Tefa
    Tefa almost 7 years
    Where to create xml file?
  • HenBoy331
    HenBoy331 almost 7 years
    in res/xml folder
  • Bloomberg58
    Bloomberg58 over 6 years
    @HenBoy331.... Hello. I tried it...It did not worked as expected...In Log.d, I get onAccessibilityEvent... I never get Log.d(TAG, text); I thought I'd get the content of the dialog box of ANY popup... But it seems I do not get into if (event.getClassName().equals("android.app.AlertDialog")) of the original tutorial
  • sma6871
    sma6871 about 6 years
    @Alex This would only be possible in an Android version earlier than 4.2.2. In 4.2.2 the IExtendedNetworkService seems to have been removed by Google due to security risk. See issue posted at Google – code.google.com/p/android/issues/detail?id=57120 android.googlesource.com/platform/packages/apps/Phone/+/…
  • HendraWD
    HendraWD almost 6 years
    If you are targetting Oreo and up, you can check here developer.android.com/reference/android/telephony/…
  • davkutalek
    davkutalek about 4 years
    @HendraWD That API only works for USSD sessions that do not require any steps
  • Hashem Alhariry
    Hashem Alhariry almost 4 years
    how to call the service ? can you send github link
  • cgb_pandey
    cgb_pandey almost 4 years
    @HashemKhaled, see an example here : umeshisran4android.blogspot.com/2015/11/…