1

I'm asking this question because my Java knowledge is really low... I need need to use this new API 27 USSD feature... Below if What I'm trying to do :

public class MyService extends IntentService {

    // BEGIN of MyService Class properties ****

    public static boolean jobInProgress = true;

    private Handler myHandler = new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg); // I guess this will be on some message queue somewhere
        }
    };


    TelephonyManager  tm;

    // END of properties *************************************

    // BEGIN of MyService class abstract class methods implementation

    class MyCallback extends TelephonyManager.UssdResponseCallback{

        Context serviceContext;

        MyCallback (Context serviceContext){
            this.serviceContext = serviceContext;
        }
        public void onReceiveUssdResponse (TelephonyManager telephonyManager,
                                           String request,
                                           CharSequence response){
            //Here since it's a System callback I guess my this.tm == telephonyManager parameter right ?
            Toast.makeText(serviceContext, "Response from network is : " + response, Toast.LENGTH_LONG).show();

            MyService.jobInProgress = false;
        }

        public  void onReceiveUssdResponseFailed (TelephonyManager telephonyManager,
                                                    String request,
                                                    int failureCode){
            Toast.makeText(serviceContext, "USSD request failed with code " + failureCode, Toast.LENGTH_LONG).show();
            MyService.jobInProgress = false;
        }
    }
    // END of abstract methods implementation******************

    //BEGIN of MyService Class methods

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service is created.", Toast.LENGTH_LONG).show();
    }

    @Override 
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service is destroyed", Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        doJob();
        while(jobInProgress){
            //I hang here to not call onDestroy to quickly...
        }
    }

    private void doJob(){

        //Get the instance of TelephonyManager
        this.tm =(TelephonyManager)getSystemService(this.TELEPHONY_SERVICE);


        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        //Don't know How to use sendUssdRequest second and thrid arguments. Below is what I have tried with no success
        this.tm.sendUssdRequest("#105*2#",new MyCallback(this),myHandler);
    }



    //END of class methods*****************************
}

The golad I'm trying to achieve is to runn the USSD request and print the result in a Toast. When I launch the service, it says service created as expected, it goes into the doJob() method as expected, but after that, nothing else happens... The app does not even crash... Just as if after enterring doJob() no instructions was written...

Can you help me make this code work ?

tom johnes
  • 387
  • 1
  • 3
  • 12
  • Have you granted the permission `CALL_PHONE`? – Sagar May 27 '18 at 02:54
  • @Sagar Yes I did... The manifest has lots of permissions – tom johnes May 27 '18 at 06:03
  • I mean have you granted the permission? Go to Settings > Apps > you app > Permissions and check if its enabled for you. – Sagar May 27 '18 at 06:25
  • @Sagar Yes it has the `Telephone` permission ; it is enabled... When I first launched the app, it asked for it and I accepted thats why it's enabled...[Here](https://androidforums.com/threads/how-to-use-api-27-telephony-manager-ussd-feature.1271192/) you can see how I reorganised my code based on [stackoverflow answer](https://stackoverflow.com/a/46890713/6266949) but I still get the same result... By the way, when I use [Intent.call_action](https://stackoverflow.com/questions/4275678/how-to-make-a-phone-call-using-intent-in-android) it works but I need to use API 27 USSD features though – tom johnes May 27 '18 at 08:00
  • Try to use normal Service instead on Intent service – Sagar May 27 '18 at 10:18

2 Answers2

1

The reason its not working is beacuse you are using Handler and infinite loop together.

When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it. So when you do following:

while(jobInProgress){
            //I hang here to not call onDestroy to quickly...
  }

It will block the worker Thread and also the Handler. As a result nothing happens.

The solution would be to use normal Service and avoid any looping.

Remember from Android O you cannot endlessly run your service in background. This approach will work if your app is in Foreground. Use foreground Service if you want to make it work reliably.

Sagar
  • 23,903
  • 4
  • 62
  • 62
  • I had a catch 22 with Services and Network operation on Main UI threads. That's why I ended using IntentService... For your answer, I think it is the reason... Which leads me to ask another question (this time is it REALLY about sendUssdRequest)... I'll post how I solved it... Please vote up my question maybe it can help somebody else... – tom johnes May 27 '18 at 19:11
  • Also I changed the title of the question...feel free to update it so it reflects better the real problem – tom johnes May 27 '18 at 19:12
  • [Here](https://stackoverflow.com/questions/50555771/android-api-27-sendussdrequest-not-able-to-parse-ussd-my-code) is a follow up of my question.. Hopeffully you can also help me there – tom johnes May 27 '18 at 19:31
0

Here is how I solved it following Sagar's answer :

Instead of :

@Override
    protected void onHandleIntent(@Nullable Intent intent) {
        doJob();
        while(jobInProgress){
            //I hang here to not call onDestroy to quickly...
        }
    }

I did this :

@Override
    protected void onHandleIntent(@Nullable Intent intent) {

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                doJob();
            }
        });

        t.start();

        while(jobInProgress){
                //I hang here to not call onDestroy to quickly...
        }
    }

and my Handler changed to this :

private Handler myHandler = new Handler(Looper.getMainLooper())
        public void handleMessage(Message msg) {
            super.handleMessage(msg); // I guess this will be on some message queue somewhere
        }
    };
tom johnes
  • 387
  • 1
  • 3
  • 12
  • I think spawning a new thread from worker Thread ( Intenservice creates a thread) is not a great idea. This will be difficult to maintain and also could cause problems during debugging. You can create a Service and then create Thread within it fo get rid of `Network call on UI thread` error. – Sagar May 27 '18 at 22:23
  • @Sagar Yes. I thought of that. I don't know why I did not do it when I first started this project. Or maybe I tried and encountered some issues... I'll go back to that becasue I like the fact that I can have control over the termation of a Service vs IntentService. – tom johnes May 28 '18 at 16:33
  • @Sagar I think I found when I chose IntentService over Service.... The second type if I'm correct is is bound to the Thread that starts it. True. But it seems it also dies when the Main Activity is destroyed.... I need a service that can remain alive all the time. That why I chose IntentServices.... Unless you tell me Services can be kept alive after the application is shut down (or Main Activity destroyed...) – tom johnes May 29 '18 at 19:41