12

Is there any way to show a modeless dialog--a dialog that allows the user to interact with whatever was on the screen before the dialog but also allows the user to interact with the dialog if pressed?

I know of Toasts, but they don't allow interaction with the popup.

I know of Dialogs, but they're modal and don't allow interaction with the background.

I know of Notifications, but I want something that is visibile on screen.

I basically want to be able to be playing a game or something and a popup appears that I have a new email or something. I can click it to view my email, but I can wait for it to go away if I just want to continue playing my game. Is this possible in Android?

MrSmith42
  • 9,961
  • 6
  • 38
  • 49
Grantland Chew
  • 2,620
  • 26
  • 26
  • Do you want your notification to appear only in your Activity or do you want it to potentially appear in other activities? – Jean Hominal Nov 09 '10 at 10:51

3 Answers3

14

Yes, create an Activity with style Theme.Dialog. This is a normal activity which looks like a dialog, while being modeless and accepting events.

An example:

<activity android:name=".activity.dialog.PhotoDialog"
          android:label="@string/photo_dialog_title"
          android:theme="@android:style/Theme.Dialog"/>

Edited:

Indeed Theme.Dialog blurs the underlying activity and makes it unaccessible. I had a similar requirement here I had to show upload progress dialog with text and cancel button. The main catch is in setting WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL and resetting WindowManager.LayoutParams.FLAG_DIM_BEHIND.

Created a Dialog with custom content:

    if (progressDialog == null) {
            progressDialog = new Dialog(activityRequestingProgressDialog);
            progressDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            progressDialog.setContentView(R.layout.progress_upload);
            progressBar = (ProgressBar) progressDialog.findViewById(R.id.progressBar);
            progressText = (TextView) progressDialog.findViewById(R.id.progressText);
            progressText.setText("0 %");
            progressText.setTextSize(18);
            Button buttonCancel = (Button) progressDialog.findViewById(R.id.btnCancel);
            buttonCancel.setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                    cancelProgressDialog();
                    stopUpload("Upload cancelled.");
                }
            });
            Window window = progressDialog.getWindow();
            window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            window.setGravity(Gravity.BOTTOM);
            progressDialog.show();
        }

        progressText.setText(text);
        progressBar.setProgress(percent);

And this is the layout for this Dialog:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/progressDialog"
          android:orientation="vertical"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:layout_centerVertical="true">

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:textSize="18sp"
          android:padding="10dp"
          android:text="@string/progress_title"/>

<LinearLayout android:id="@+id/progressDialog"
              android:orientation="horizontal"
              android:layout_height="wrap_content"
              android:layout_width="wrap_content"
              android:padding="10dp"
              android:layout_centerVertical="true">

    <ProgressBar android:id="@+id/progressBar"
                 android:layout_width="150dp"
                 android:layout_height="34dp"
                 android:paddingRight="10dp"
                 android:max="100"
                 android:progress="0"
                 android:fadingEdge="vertical"
                 style="?android:attr/progressBarStyleHorizontal"/>

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="center"
              android:id="@+id/progressText"
              android:paddingRight="10dp"/>

    <Button android:layout_height="40dp"
            android:layout_width="80dp"
            android:id="@+id/btnCancel"
            android:text="@string/dialog_cancel"/>

</LinearLayout>
</LinearLayout>
Peter Knego
  • 79,991
  • 11
  • 123
  • 154
  • would this still allow interaction with the activity behind it? – Grantland Chew Nov 13 '10 at 03:18
  • so i tested it to make sure and it actually blurs out the activity behind it as i thought... – Grantland Chew Nov 16 '10 at 08:52
  • 1
    You are right. I mixed this with some other solution. I posted the right code now. – Peter Knego Nov 16 '10 at 09:55
  • Thanks! I actually found it on my own and did it by manually creating the view manually and using the WindowManager to add it. This way might be better as it doesn't have to interact with the WindowManager directly. By the way, why do you set FLAG_NOT_TOUCH_MODAL twice? – Grantland Chew Nov 17 '10 at 20:37
  • The signature of this method is `window.setFlags(flag, mask)`. Using it with (flag, flag) makes sure that other flags are not changed. Actually it's better to use `addFlag(flag)` as it does the same thing with less ambiguity. – Peter Knego Nov 17 '10 at 20:43
  • Hello, how would i customise the layout of the alert? – newton_guima Oct 24 '13 at 14:08
  • This allows to show the dialog and interact with the background, but what if in the background you have some edit text, and you click into it? Would the keyboard be shown in that case? – Witold Kupś Jun 07 '21 at 05:03
4

just add FLAG_NOT_TOUCH_MODAL flag to your dialog

dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);  
efeyc
  • 2,122
  • 2
  • 27
  • 39
0

My implementation which was a little more hackish but also allows button presses to be caught by background window

_wm = this.getWindowManager();
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
_view = layoutInflater.inflate(R.layout.notification, null);

_params = new WindowManager.LayoutParams();
_params.height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
_params.width = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
_params.flags = 
    // this is to keep button presses going to the background window
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
    // this is to enable the notification to recieve touch events
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
// background transparant
_params.format = PixelFormat.TRANSLUCENT;
_gravity = Gravity.TOP;//Gravity.BOTTOM;

_wm.addView(_view, _params);
Grantland Chew
  • 2,620
  • 26
  • 26
  • works fine in many cases... but I have a listview behind this dialog and I can not select any listview elt... any advice to make listview element clickable ? – fvisticot Feb 22 '13 at 17:59