21

I'm wanting to write a widget displays the users' prepay balance, remaining data etc.

I'm thinking of automatically calling the USSD code which returns this data (will have to have a regex for each network), at intervals (not often, to save battery). This would have to be done in the background. I have an app at the moment which runs the ussd code and returns the result, so I think this should be possible - but I'm not sure how it would be done in the background.

I've seen the intents for Calling a number, but I'm not sure how to get the result, and I'm also thinking that that intent would cause the call screen to come up into the foreground?

The other option is to get the data by screen-scraping the result from the carrier's website/maybe wap site but that would result in data charges for the user, so I would prefer a solution using the USSD code.

Thanks in advance for any help - only started working on understanding android today so got quite a lot to learn :)

Jords
  • 1,855
  • 3
  • 18
  • 28
  • I'm actually not even sure If I can make a call from a service - I tried creating a ACTION.CALL intent and sending it with startActivity(), but this causes a force close, even If I set the FLAG_ACTIVITY_NEW_TASK flag. – Jords Nov 20 '10 at 09:19
  • Silly me, Just didn't have the right permissions. It's actually calling the USSD code now - but not in the background. I guess you can't make an android call without the dialer displaying it's interface - will have to go with the web option I think. – Jords Nov 20 '10 at 22:44
  • Hi Jords, I see this question was asked 2 years ago so I hope things have changed since then. I'm writing similar application (as part of my diploma). Could you please help me with the USSD task. Just like you I need to perform a USSD call and get result (in the background if possible)... I'll appreciate if you share some working code on this. Thanks – vach Oct 30 '13 at 09:12

8 Answers8

14

USSD is not yet supported on Android. There is a feature request for it: http://code.google.com/p/android/issues/detail?id=1285

Peter Knego
  • 79,991
  • 11
  • 123
  • 154
  • Thanks, this isn't exactly the answer I was going for but answers my question at least and hopefully it will be in Gingerbread. I'm amazed I never found that from my searching! – Jords Nov 21 '10 at 04:30
  • And we still don't have it – gkiko Nov 18 '13 at 16:01
  • Look at answer from Picaso and Agarwal Shankar, now it is possible – Musa Haidari Jan 07 '16 at 15:38
  • 1
    @Musa: it seems you can initiate a USSD call (user sees the dialog and has to press Call), but you can not (at least not anymore) parse the response: http://stackoverflow.com/questions/28083067/how-to-read-intercept-ussd-message-comming-on-android-phone – Peter Knego Jan 07 '16 at 16:16
8

You can send a USSD code by below code and also you need to add permission (This should be a run time permission after Marshmallow update)

    <uses-permission android:name="android.permission.CALL_PHONE" />

    String code = "*" + Uri.encode("#") + 456 + Uri.encode("#");
    startActivity(new Intent("android.intent.action.CALL", Uri.parse("tel:" + code)));

And you can read USSD codes by AccessibilityService

Here is the example:

Service:

public class USSDService extends AccessibilityService {
    private static final String TAG = "USSDService";

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d(TAG, "onAccessibilityEvent");
        String text = event.getText().toString();
        Log.d(TAG, text);
        }
    }

    @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;
        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
        setServiceInfo(info);
    }
}

AndroidManifest.xml :

<service android:name=".services.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/config_service" /> // created below
</service>

res/xml/config_service.xml :

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_description"
    android:notificationTimeout="100"
    android:packageNames="com.cootf.sims"
    android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />

Run the code --> Enable the accessibility through Settings --> Accessibility --> [Your app name] --> Enable. Job Done!

  • Thanks, this is working method. Checked on Android 7. Related article with comments - http://umeshisran4android.blogspot.com/2015/11/how-to-readparse-ussd-messages.html – Anton Samokat Nov 27 '22 at 23:29
6

You can use the following code to call the ussd codes on android phone to check the balance and etc......

   String s=calledittext.getText.toString();//calledittext is editText on the 
  //screen   from  which  can get the number
          if((s.startsWith("*"))&&(s.endsWith("#"))){
            //if true then it is a USSD call----
            callstring=s.substring(0, s.length()-1);
            callstring=callstring+Uri.encode("#");

    Log.d("CALL TYPE---------->", "USSD CALL"); 
        }else{
            callstring=s;   
    Log.d("CALL TYPE---------->", "Not a USSD CALL");   
    //Intent i=new Intent(android.content.Intent.ACTION_CALL,Uri.parse("tel:"+output.getText().toString()));
    //startActivity(i);
        }
    Intent i=new Intent(android.content.Intent.ACTION_CALL,Uri.parse("tel:"+callstring));
    startActivity(i);
picaso
  • 713
  • 2
  • 14
  • 26
5

I'm not completely sure but I think USSD is not yet supported on android, however you can try this workaround:

startActivity(new Intent("android.intent.action.CALL",Uri.parse("tel:*123" + Uri.encode("#")));
Shankar Agarwal
  • 34,573
  • 7
  • 66
  • 64
5

Android O(API level 26) adds a sendUssdRequest method to the TelephonyManager, which also includes a callback for getting the result for the request.

The docs.

karuhanga
  • 3,010
  • 1
  • 27
  • 30
1

USSD call interuptn is not yet supported n Android

shanko'o
  • 31
  • 1
0

Android 8 (Oreo) and above now supports this. Here is the code. The TelephonyManager class is used to achieve this.

 public void dialUssdToGetPhoneNumber(String ussdCode, int sim) {

    if (ussdCode.equalsIgnoreCase("")) return;



    if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 234);
        return;
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {


        TelephonyManager manager = (TelephonyManager) getActivity().getSystemService(TELEPHONY_SERVICE);
        TelephonyManager manager2 = manager.createForSubscriptionId(2);

        TelephonyManager managerMain = (sim == 0) ? manager : manager2;

        managerMain.sendUssdRequest(ussdCode, new TelephonyManager.UssdResponseCallback() {
            @Override
            public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) {
                super.onReceiveUssdResponse(telephonyManager, request, response);

                Log.e("TAG", "onReceiveUssdResponse:  Ussd Response = " + response.toString().trim() );
        
               

            }

            @Override
            public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) {
                super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode);

                Log.e("TAG", "onReceiveUssdResponseFailed: " + "" + failureCode + request);
            }
        }, new Handler());
    }

}
Ismail Osunlana
  • 434
  • 5
  • 9
0

For anyone still looking for a solution to this, there's a platform called AutoUssd (https://autoussd.com) which allows you to do exactly this. It also supports multi-step USSD sessions...

Kwame Opare Asiedu
  • 2,110
  • 11
  • 13