87

I am trying to prevent an AlertDialog box from closing when pressing the back button in Android. I have followed both of the popular methods in this thread, and with System.out.println I can see that in both cases the code executes. However, the back button still closes the dialog box.

What could I be doing wrong? Ultimately I'm trying to prevent the back button closing a dialog box - it is a disclaimer that is displayed the first time the app is run and I don't want the user to have any option but to press the "Accept" button in order for the app to continue.

4
  • 1
    If you require a user to accept a license or disclaimer (or whatever) then you MUST allow them to refuse. If they click the BACK button then make sure your license/disclaimer dialog appears again next time they start the app and again and again until they either accept or remove the app from their device. If you choose to use the approach suggested by Sam then you MUST provide a 'Refuse' button but then re-create the license/disclaimer next time they start the app.
    – Squonk
    Commented Aug 27, 2012 at 23:08
  • 1
    I would remove an app that gives me "accept" as the only option... and don't even think about disabling the home button! Commented Aug 27, 2012 at 23:49
  • 1
    The app can be closed through pressing the home button, but essentially the app cannot progress past the disclaimer if the license is not accepted. @Squonk, you mention that I must allow them to refuse; is this a legal issue? i.e. is there a law that software must be usable (if it has been paid for) without accepting the licence agreement? n.b. I already have a 'decline' button, and pressing this pops up a Toast() saying that you must accept the agreement in order to use the app. The dialog box thus persists until accept is pressed. Commented Aug 28, 2012 at 14:37
  • 1
    @CaptainProg : I'm not a lawyer but I suspect in some countries it might be considered a legal issue. I'm not suggesting that you allow people to use you app if they refuse/decline the disclaimer. All I'm saying is it is bad policy, bad customer relations (even if the app is free) and bad for the UX to lock somebody in. Simply have the 'decline' option close the app and next time the user tries to start it, present the same dialog. Don't just popup a Toast, leave them locked in and rely on them using thw HOME button to get out.
    – Squonk
    Commented Aug 28, 2012 at 20:47

9 Answers 9

190

Simply use the setCancelable() feature:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(false);

This prevents the back button from closing the dialog, but leaves the "negative" button intact if you chose to use it.


While any user that does not want to accept your terms of service can push the home button, in light of Squonk's comment, here two more ways to prevent them from "backing out" of the user agreement. One is a simple "Refuse" button and the other overrides the back button in the dialog:

builder.setNegativeButton("Refuse", new OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               finish();
           }
       })
       .setOnKeyListener(new OnKeyListener() {
           @Override
           public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
               if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP)
                   finish();
               return false;
           }
       });
2
  • 44
    Additionally, If using a DialogFragment, you should call setCancelable on that and not on the Dialog itself
    – Kuffs
    Commented Aug 21, 2015 at 8:05
  • thanks a lot @Kuffs. I was setting it on the Dialog and wondering why it isn't working !
    – sasikt
    Commented Oct 7, 2015 at 6:04
25

To prevent the back button closes a Dialog (without depending on Activity), just the following code:

alertDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        // Prevent dialog close on back press button
        return keyCode == KeyEvent.KEYCODE_BACK;
    }
});
2
  • 1
    Worked beautifully in my case. I had to load a WebView on my app. I had to check canGoBack() and close the dialog if it was false.
    – Aloha
    Commented Jun 10, 2016 at 14:40
  • 1
    worked well. keep it up Commented Nov 19, 2021 at 8:02
24

When using DialogFragment you will need to call setCancelable() on the fragment, not the dialog:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    dialog = new ProgressDialog(getActivity());
    dialog.setIndeterminate(true);
    dialog.setMessage(...);
    setCancelable(false);

    return dialog;
}

Calling dialog.setCancelable() seem to have no effect. It seems that DialogFragment does not takes notice of the dialog's setting for cancelability.

4

Use setCancelable(false)

SampleDialog sampleDialog = SampleDialog.newInstance();
sampleDialog.setCancelable(false);
sampleDialog.show(getSupportFragmentManager(), SampleDialog.class.getSimpleName());
1

Only this worked for me:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(title);
builder.setMessage(content);

/**
 * Make it when the Back button is pressed, the dialog isn't dismissed.
 */
builder.setOnKeyListener(new DialogInterface.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
            Utilities.makeToast(getContext(), "There is no way back!");
            return true; // Consumed
        }
        else {
            return false; // Not consumed
        }
    }
});

Dialog dialog = builder.create();

/**
 * Make it so touching on the background activity doesn't close the dialog
 */
dialog.setCanceledOnTouchOutside(false);

return dialog;

As you can see, I also added a dialog.setCanceledOnTouchOutside(false); line so tapping outside of the dialog doesn't result in it being closed either.

1

In JQuery Mobile a popup adds a hash to the url, the following code allows the back to dismiss the popup when open and return to the app when closed. You could use the same logic for a custom ui framework.

@Override
public void onBackPressed() {

    // check if modal is open #&ui-state=dialog

    if (webView.getVisibility() == View.VISIBLE && webView.getUrl().contains("#&ui-state=dialog")) {
        // don't pass back button action
        if (webView.canGoBack()) {
            webView.goBack();
        }
    } else {
        // pass back button action
        super.onBackPressed();
    }
}
1

Add setCancelable(false) to stop the back button from closing a dialog box.

For example :

AlertDialog.Builder builder = AlertDialog.Builder(this)
Dialog dialog = builder.create()
dialog.setCancelable(false)
dialog.setCanceledOnTouchOutside(false)

This will prevent the user from canceling the dialog when they press the back button or touch outside the dialog window

1

Go ahead with this one:

 ProgressDialog progressDialog = new ProgressDialog(ChatActivity.this);
    progressDialog.setMessage("sending video...");
    progressDialog.setCanceledOnTouchOutside(false);
    progressDialog.setCancelable(false);
    progressDialog.show();
0

for Kotlin you can simply do this:

alertDialog.setOnKeyListener(DialogInterface.OnKeyListener { _: DialogInterface?, keyCode: Int, _: KeyEvent? -> keyCode == KeyEvent.KEYCODE_BACK })

Not the answer you're looking for? Browse other questions tagged or ask your own question.