85

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.

Community
  • 1
  • 1
CaptainProg
  • 5,610
  • 23
  • 71
  • 116
  • 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 Aug 27 '12 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! – WarrenFaith Aug 27 '12 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. – CaptainProg Aug 28 '12 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 Aug 28 '12 at 20:47

9 Answers9

188

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;
           }
       });
Sam
  • 86,580
  • 20
  • 181
  • 179
  • 44
    Additionally, If using a `DialogFragment`, you should call `setCancelable` on that and not on the `Dialog` itself – Kuffs Aug 21 '15 at 08:05
  • thanks a lot @Kuffs. I was setting it on the Dialog and wondering why it isn't working ! – sasikt Oct 07 '15 at 06: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;
    }
});
falvojr
  • 3,060
  • 4
  • 31
  • 54
22

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.

Ognyan
  • 13,452
  • 5
  • 64
  • 82
4

Use setCancelable(false)

SampleDialog sampleDialog = SampleDialog.newInstance();
sampleDialog.setCancelable(false);
sampleDialog.show(getSupportFragmentManager(), SampleDialog.class.getSimpleName());
David
  • 37,109
  • 32
  • 120
  • 141
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.

ban-geoengineering
  • 18,324
  • 27
  • 171
  • 253
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();
    }
}
Ricardo Saracino
  • 1,345
  • 2
  • 16
  • 37
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

StuStirling
  • 15,601
  • 23
  • 93
  • 150
Iancu Vlad
  • 41
  • 2
  • 2
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 })
Sep
  • 147
  • 8