• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

How to use API 27 telephony manager USSD feature ?

Hello guyz,
I found a code at stackoverflow... I run this code in an IntenService method onHandleIntent. But nothing happens. The app does not even crash... What I'm trying to do is launch a USSD request and print the result in a Toast. Below is the code I tried

Java:
private void doJob(){

    if (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(mActivityRef.get(),
                new String[]{Manifest.permission.CALL_PHONE},
                MY_PERMISSION_CALL_PHONE);
    }

    TelephonyManager   telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
    Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message message) {
            Log.e("ussd",message.toString());
        }
    };
    TelephonyManager.UssdResponseCallback callback = new TelephonyManager.UssdResponseCallback() {
        @Override
        public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) {
            super.onReceiveUssdResponse(telephonyManager, request, response);
            Log.e("ussd","Success with response : " + response);
        }

        @Override
        public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) {
            super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode);
            Log.e("ussd","failed with code " + Integer.toString(failureCode));
        }
    };

    try {
        Log.e("ussd","trying to send ussd request");
        telephonyManager.sendUssdRequest("#106#",
                callback,
                handler);
    }catch (Exception e){


        String msg= e.getMessage();
        Log.e("DEBUG",e.toString());
        e.printStackTrace();
    }


}
 
Last edited:
A couple of things:-

- Does the app ask you to grant CALL_PHONE permission? It would normally pop up a dialog asking for confirmation.
- Don't use Toast to debug your app. Verify that the callback method is being called. Run the app in debug mode, and set a breakpoint in the onReceiveUssdResponse() method. Does it get hit?
 
A couple of things:-

- Does the app ask you to grant CALL_PHONE permission? It would normally pop up a dialog asking for confirmation.
- Don't use Toast to debug your app. Verify that the callback method is being called. Run the app in debug mode, and set a breakpoint in the onReceiveUssdResponse() method. Does it get hit?

Yes the app asked for it and I granted it... For the debug, since I'm using a while(true)
A couple of things:-

- Does the app ask you to grant CALL_PHONE permission? It would normally pop up a dialog asking for confirmation.
- Don't use Toast to debug your app. Verify that the callback method is being called. Run the app in debug mode, and set a breakpoint in the onReceiveUssdResponse() method. Does it get hit?

Hey,
Thanks for replying.
- The pop up for permission did show. I accepted. I also check in Application settings and I saw that Telephone permission is enabled... So the problem is not there (I guess)
- I used `Log.d` insteadof `Toast` to debug... I place a break point where you've suggested. It is never reached... The line of
Java:
manager.sendUssdRequest("#106#",  ...
seem to never be executed or crashes SILENTLY
- Now I tried to use the good old method like below :
Java:
Intent intent = new Intent(Intent.ACTION_CALL,
                Uri.parse("tel:" + Uri.encode("#106#")));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Needed since calling an Activity from outside an Activity
        getBaseContext().startActivity(intent);
This code is written right above
Java:
manager.sendUssdRequest("#106#"....
.
Obviously, this code worked fine... The old code with Intent.ACTION_CALL works fince but I need to use API 27 USSD features
 
Last edited:
A couple of things:-

- Does the app ask you to grant CALL_PHONE permission? It would normally pop up a dialog asking for confirmation.
- Don't use Toast to debug your app. Verify that the callback method is being called. Run the app in debug mode, and set a breakpoint in the onReceiveUssdResponse() method. Does it get hit?


Hello,
this s a second reply... I'm working on the code right now so...
I found something at stackoveflow, but I alway get the following error : USSD_RETURN_FAILURE
But the same ussd code was used with Intent.ACTION_CALL and it worked fine with it...
What do you think of that ? Is sendUssdRequest able to properly send the ussd code to the network ? How can I be sure or debug that ?

Also I think I'g getting the famous Connection problem or invalid MMI Code . My phone is a dual SIM and I let all settings to default... Dialing the ussd code in the native caller app does not fail nor prompt for choosing sim/netwokr.. Only one sim in slot 2 in the phone
 
Last edited:
In that code you cobbled from SO, you took out the try..catch block which surrounds the sendUssdRequest() call. Bad idea.

But anyway, let me point out a basic misunderstanding you have, regarding asking for permissions. In fact a remarkably similar question came up on this forum recently.

In essence, any code you put after this block, will not have permission granted, even if the user gave it

Code:
if (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(mActivityRef.get(),
                    new String[]{Manifest.permission.CALL_PHONE},
                    MY_PERMISSION_CALL_PHONE);
        }

Why?
Because the dialog you see displayed is executed asynchronously, in parallel to the main thread of execution, which happily goes on and tries to do a sendUssdRequest(), without having the correct permission (CALL_PHONE) to do it. The thread dialog is still waiting there for you to grant that permission.
Now because you took out the try..catch block, the 'permission denied' exception is probably getting ignored.

What you should be doing, is putting the call to sendUssdRequest() into the permission callback handler, which is onRequestPermissionsResult(). It's a classic callback notification pattern. See here for more details on how to code it:

https://developer.android.com/training/permissions/requesting
 
In that code you cobbled from SO, you took out the try..catch block which surrounds the sendUssdRequest() call. Bad idea.

But anyway, let me point out a basic misunderstanding you have, regarding asking for permissions. In fact a remarkably similar question came up on this forum recently.

In essence, any code you put after this block, will not have permission granted, even if the user gave it

Code:
if (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(mActivityRef.get(),
                    new String[]{Manifest.permission.CALL_PHONE},
                    MY_PERMISSION_CALL_PHONE);
        }

Why?
Because the dialog you see displayed is executed asynchronously, in parallel to the main thread of execution, which happily goes on and tries to do a sendUssdRequest(), without having the correct permission (CALL_PHONE) to do it. The thread dialog is still waiting there for you to grant that permission.
Now because you took out the try..catch block, the 'permission denied' exception is probably getting ignored.

What you should be doing, is putting the call to sendUssdRequest() into the permission callback handler, which is onRequestPermissionsResult(). It's a classic callback notification pattern. See here for more details on how to code it:

https://developer.android.com/training/permissions/requesting

Oh no no... I did not take out the try - catch... Actually I did not update my Original Post code... I just did. In it you can see the try catch is there... Also I'm using Loginstead of toast to debug, as you've suggested. Still it goes for the failure code I've described about : Connection problem or invalid MMI Code and in Logcat I see the log of onReceiveUssdResponseFailed i.e failed with code -1
It looks like sendUssdRequest is not able to parse my ussd string #106# ... I put my phone in 2G , 3G, but same result... Also in app settings, the app has the permissions... BUT I'm working on doig it as you've said in your last reply. It'll be tricky though since onRequestPermissionsResult is mostly overriden in Activity class not in
IntentService class... but I'm working on it
 
Last edited:
In that code you cobbled from SO, you took out the try..catch block which surrounds the sendUssdRequest() call. Bad idea.

But anyway, let me point out a basic misunderstanding you have, regarding asking for permissions. In fact a remarkably similar question came up on this forum recently.

In essence, any code you put after this block, will not have permission granted, even if the user gave it

Code:
if (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(mActivityRef.get(),
                    new String[]{Manifest.permission.CALL_PHONE},
                    MY_PERMISSION_CALL_PHONE);
        }

Why?
Because the dialog you see displayed is executed asynchronously, in parallel to the main thread of execution, which happily goes on and tries to do a sendUssdRequest(), without having the correct permission (CALL_PHONE) to do it. The thread dialog is still waiting there for you to grant that permission.
Now because you took out the try..catch block, the 'permission denied' exception is probably getting ignored.

What you should be doing, is putting the call to sendUssdRequest() into the permission callback handler, which is onRequestPermissionsResult(). It's a classic callback notification pattern. See here for more details on how to code it:

https://developer.android.com/training/permissions/requesting

Still working on it... sendUssdRequest() method requires checkPermission. So putting it in
onRequestPermissionsResult will require to check for permission inside that callback... This could probably create in infinite loop I guess... It's not helping my case (or I don't know how to use it)... Android developper example is about starting a Camera Activity... My is about triggering a method which itself need permission...Here is the example https://github.com/googlesamples/an...le/android/basicpermissions/MainActivity.java
So far, I won't be able (or should I say I'm not able) to use onRequestPermissionsResult as you've requested... Anyway, in my code (please se OP it was updated) try catch never talks about permission missing....
 
Don't use Log statements to debug your code. Do what I recommend, and run the app in debug mode. Set breakpoints at appropriate points in your code, and step through the code execution, examining the values of variables, return codes, and error messages.
 
Don't use Log statements to debug your code. Do what I recommend, and run the app in debug mode. Set breakpoints at appropriate points in your code, and step through the code execution, examining the values of variables, return codes, and error messages.

Still with the code that is right now in my first post... After setting debug points everywhere, I found that something strange happens...
- sendUssdRequest will ALWAYS result in going to onReceiveUssdResponseFailed with code USSD_RETURN_FAILURE
- but using debugging, I saw that my USSD request actually works FINE. But the response is not in onReceiveUssdResponse. Rather, it is a method called onReceiveResult. That method is overriden inside sendUssdRequest source code with the following
Java:
protected void onReceiveResult(int resultCode, Bundle ussdResponse)
So something makes the code directly jump to onReceiveUssdResponseFailed while in reality, some part of sendUssdRequest works fine. As you can see in the image below (sorry I had to hide private data), when I chose onReceiveResult in debug mode, even if resultCode = -1, the variable "response" contains the actual reply I'm waiting from the ussd command I executed. The only problem is that it is not passed to onReceiveUssdResponse... This is strange...

I don't think it's related to permission since I can see the USSD request was actually done. The thing that remains on the phone is the Connection problem or invalid MMI Code thing

It seems I can't upload image... here's a link https://ibb.co/dMLZJJ
dMLZJJ
 
There's some information on how to correctly construct a USSD request here:

https://stackoverflow.com/questions/5477597/how-is-it-possible-to-do-ussd-requests-on-android

Hello.
Problem solved... Actually, the USSD request code I was using triggers a multisession USSD ; for instance press 1 for balance , 2 for data connection, etc... So I guess sendUssdRequest network reply handler was not able to understand the network reply for the multisession USSD.
Therefore, I used a full USSD string i.e with all the intermediate steps and `sendUssdRequest` worked as expected.....

Thanks you for your help mate
 
Hey guys, I managed to bypass some of the problems with (like the multisession USSD responses not working) by using Reflection. I've made a GitHub gist here: https://gist.github.com/posei/1e5ae219329aa1015d3c55c3982352c5

Obviously the assumption is the correct permissions (only `CALL_PHONE` at this point) are given - In terms of Contexts, I've only ever run this in an Activity but I think it would work fine in most if not all/any.

The next thing is figuring out how to sustain the session, if at all possible.
 
Hey guys, I managed to bypass some of the problems with (like the multisession USSD responses not working) by using Reflection. I've made a GitHub gist here: https://gist.github.com/posei/1e5ae219329aa1015d3c55c3982352c5

Obviously the assumption is the correct permissions (only `CALL_PHONE` at this point) are given - In terms of Contexts, I've only ever run this in an Activity but I think it would work fine in most if not all/any.

The next thing is figuring out how to sustain the session, if at all possible.

Haha you must be a genius of java expert or something.... I read about Reflection still on almost the same topic (sms and ussd in android)... It's too advanced for me. I would not implement it on a production project since I've not enough skill to debug such a code... I read you code at github. The only reason I was able to follow is obviously because of all the post above here....
I'm pretty impressed to see you are able to override onReceiveResult with Reflection
Now in my case, as I said, set the full USSD code to avoid a multisession USSD solved the issue.
You code works fine. But I wish it was able to maintain the USSD session. If it was, I think google should contact you since they have not solved this issue yet...
You should try and ask for help here or at stackoverflow. You are really close to solve a BIG flaw in the SDK....
As I said, I'm not expert in Java (barely OCA Java skills)... I would have contributed more... Anyways I'm going to see what I can you if at all possible from my side...
 
Hello, Please I am experiencing this error with the code, Kindly help me out.


java.lang.NoClassDefFoundError: Failed resolution of: Landroid/telephony/TelephonyManager$UssdResponseCallback;
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1078)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2616)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)

Caused by: java.lang.ClassNotFoundException: Didn't find class "android.telephony.TelephonyManager$UssdResponseCallback" on path: DexPathList[[zip file "/data/app/ussd.code.myapplication-2/base.apk"],nativeLibraryDirectories=[/data/app/ussd.code.myapplication-2/lib/arm, /system/lib, /vendor/lib, /system/vendor/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1078)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2616)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
 
Back
Top Bottom