15

I have issue with displaying AlertDialog from Service. I am able to display custom layout window using Toast or using WindowManager(TYPE_SYSTEM_ALERT or TYPE_SYSTEM_OVERLAY). But, I do not want to use custom layout, I prefer to use nice AlertDialog GUI directly.

Scenario:

  • Running Service. No active Activity present.
  • On some external event, Service sends Notification
  • When user press Notification, Service is informed via PendingIntent and AlertDialog should be displayed (created with AlertDialog.Builder(this))

Error:

ERROR/AndroidRuntime(1063): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

Searching for the answer lead me to impression that I am trying something that is currently not possible (Android 2.2). Or maybe it is.

Pratik
  • 30,639
  • 18
  • 84
  • 159
Zelimir
  • 11,008
  • 6
  • 50
  • 45
  • Possible duplicate of [Alert dialog from Android service](http://stackoverflow.com/questions/3599563/alert-dialog-from-android-service) – araks Nov 06 '15 at 17:36

2 Answers2

26

Solution that matches described scenario has been found.

  • New Activity has been created and started from Service. However, it is activity with translucent background. Such activity does not have line super.setContentView() in onCreate(). More important, to ensure transparency

    @android:style/Theme.Translucent

is entered under Theme tag for this activity in AndroidManifest.xml GUI. So, new line added to the manifest xml is

android:theme="@android:style/Theme.Translucent"

  • In onCreate() actual display of AlertDialog occurs

  • Press on AlertDialog buttons causes Dialog and Activity closing and sending of the Intent (or use of some other means) to deliver result to the Service.

  • Be sure that you defined setOnDismissListener() for the Dialog (implementation should call finish() on activity). If you do not do that press on the Back key cancels dialog but leaves you in the current activity which is transparent and looks to user like something is really wrong.

brunobowden
  • 1,492
  • 19
  • 37
Zelimir
  • 11,008
  • 6
  • 50
  • 45
  • Zelimir,thank you very much. I have same problem and I am exactly looking for this. – Amitku Apr 27 '11 at 06:40
  • I am glad that it was helpful. Best regards. – Zelimir Apr 27 '11 at 12:12
  • Please correct me if I'm wrong. isn't the problem with translucent is that it is just a mirror of what is behind? e.g. if it is over the incoming call screen. You can't really answer the phone right? because your activity is blocking it (although translucent?) – Guy Jan 02 '12 at 08:11
  • Mirror? You mean it is glass window, transparent, you can see through it. Yes, if it is over incoming call screen, and it is only translucent, you cannot answer the activity below. For that reason you need to finish activity with translucent background once user selects some option or cancels it. BTW, incoming call screen for the Native phone dialer is of the type TYPE_SYSTEM_OVERLAY so you cannot put something over it while in foreground. – Zelimir Jan 02 '12 at 10:21
  • Can you expand a bit on how you deliver the result to the service? How do I let the service know that the user has selected Allow or Deny button? – Aswin Parthasarathy Nov 04 '12 at 08:29
  • Since it is not possible to use startActivityForResult() to return result to Service, I have used custom intent. Broadcast intent is sent from popup dialog activity and received in BroadcastReceiver registered in Service. – Zelimir Nov 04 '12 at 14:15
  • I have checked my original code (I should have done it before writing last response). In fact I have used startService() to return the result. Thanks to Aswin Parthasarathy and Programus for rising this question. – Zelimir Nov 12 '12 at 07:31
6

Thank you for your solution. I faced the same problem and worked out with your help.

I put this answer just to share my way for passing result back to the service.

I didn't create any additional custom intent class and solved the result passing problem by only Intent.putExtra() methods with some tricks.

In the service, use this code to start the DialogActivity which display the alert dialog in onCreate().

Intent intent = new Intent(this.getApplicationContext(), DialogActivity.class); 
intent.putExtra(DialogActivity.CLASS_KEY, this.getClass().getCanonicalName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

And in the DialogActivity, finish it like this:

private void returnOk(boolean ok) {
    Intent srcIntent = this.getIntent();
    Intent tgtIntent = new Intent();
    String className = srcIntent.getExtras().getString(CLASS_KEY);
    Log.d("DialogActivity", "Service Class Name: " + className);
    ComponentName cn = new ComponentName(this.getApplicationContext(), className);
    tgtIntent.setComponent(cn);
    tgtIntent.putExtra(RESULT_KEY, ok ? RESULT_OK : RESULT_CANCEL);
    this.startService(tgtIntent);
    this.finish();
}

At last, in the service, override the onStartCommand() method and get the result from the intent.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    int ret = super.onStartCommand(intent, flags, startId);
    Bundle extras = intent.getExtras();
    if (extras != null) {
        int result = extras.getInt(DialogActivity.RESULT_KEY, -1);
        if (result >= 0) {
            if (result == DialogActivity.RESULT_OK) {
                // Your logic here...
            }
        } else {
            // Your other start logic here...
        }
    }
    return ret;
}

I am not sure whether this way is a good solution, at least it works for me. Hope this will be helpful for someone else like me.

The complete source can be found here:

Programus
  • 338
  • 2
  • 16