Back pressed events with system alert window

4.6k views Asked by At

I need to dismiss system alert window on back pressed and home button event.I have tried with onKeyEvent but in vain. As we can't capture the back pressed event in a service, how to achieve this?

10

There are 10 answers

0
Lionell Libarios On
@Override
public void onBackPressed()
{
       super.onBackPressed();
}

Declare this on your activity. super.OnBackPressed automatically calls back method in android. it will surely cancel your dialog.

in addition, your dialog must look like this.

AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder1.setMessage("TEST DIALOG.\n");
    builder1.setPositiveButton("Ok",
            new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                Toast.makeText(MainActivity.this, "This Is test Dialog", Toast.LENGTH_SHORT).show();
        }
    });
    AlertDialog alert11 = builder1.create();
    alert11.show();

or you can set Negative button..

Hope this helps!

0
sasikumar On

Use the code below

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        exitByBackKey();

        //moveTaskToBack(false);

        return true;
    }
    return super.onKeyDown(keyCode, event);
    }

    protected void exitByBackKey() {

    AlertDialog alertbox = new AlertDialog.Builder(this)
    .setMessage("Do you want to exit application?")
    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {

        // do something when the button is clicked
        public void onClick(DialogInterface arg0, int arg1) {

            finish();
            //close();


        }
    })
    .setNegativeButton("No", new DialogInterface.OnClickListener() {

        // do something when the button is clicked
        public void onClick(DialogInterface arg0, int arg1) {
                       }
    })
      .show();

    }
0
santosh gore On

use below method to handle back button pressed.

  public void onBackPressed()
  {
        super.onBackPressed();
  }
0
Abhilash On

It's simple. Follow these steps:

  1. Create a view like Relative Layout, Linear Layout or Frame Layout Dynamically. 2. Override the dispatchKeyEvent while creating the view.
  2. Add your original view into this dynamically created view with addView() method.
  3. Add the dynamically created view to your Window Manager or Alert Dialog whichever you want.
0
khcpietro On

In addition to @Eliran Kuta's solution, this is more simple answer for Back button.

val view = getAlertView()
val windowParam = WindowManager.LayoutParams(
    WindowManager.LayoutParams.WRAP_CONTENT, // whatever
    WindowManager.LayoutParams.WRAP_CONTENT, // whatever
    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // use WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY before Oreo
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // whatever
    PixelFormat.TRANSLUCENT // whatever
)

view.isFocusableInTouchMode = true
view.setOnKeyListener { view, keyCode, event ->
    when (keyCode) {
        KeyEvent.KEYCODE_BACK -> {
            // do your work here
            true
        }
        else -> false
    }
}

val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.addView(view, windowParam)
4
Mattia Maestrini On

Define a custom layout and override dispatchKeyEvent, for example:

public class CustomSystemAlertWindow extends FrameLayout {

    public static final String TAG = "CustomSystemAlertWindow";

    private WeakReference<Context> mContext;

    public CustomSystemAlertWindow(Context context) {
        super(context);

        mContext = new WeakReference<Context>(context);

        // Set a background color to identify the view on the screen
        this.setBackgroundColor(getResources().getColor(android.R.color.holo_red_light));
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            Log.d(TAG, "back button pressed");

            if (mContext != null && mContext.get() != null) {
                WindowManager wm = (WindowManager) mContext.get().getSystemService(Context.WINDOW_SERVICE);
                wm.removeView(this);
            }

            return true;
        }

        return super.dispatchKeyEvent(event);
    }
}

Then add the view with this code:

CustomSystemAlertWindow customSystemAlertWindow = new CustomSystemAlertWindow(context);

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
        PixelFormat.TRANSLUCENT);

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
wm.addView(customSystemAlertWindow, params);

When you press the back button the view will dismiss.

4
Venkatesh Selvam On
  1. Show the Alert window through the Activity so you can detect it.

Implement the code to detect easily Back Button or Home Button pressed.

public class alertPopup extends Activity {

    Context context;
    final AlertDialog alertDialog;
    String TAG = "your Activity Name"
    boolean homePressed = false; // to detect the Homebutton pressed

    @Override
    public void onCreate(Bundle savedInstanceState) {
     AlertDialog.Builder builder = newAlertDialog.Builder(YourActivity.this, R.style.AppCompatAlertDialogStyle);
     builder.setTitle("AlertDialog Title");
            ..........
            ....... // Build ur AlertDialog

     alertDialog= builder.create();
     alertDialog.show();


         //to detect Alert Dialog cancel when user touches outside the Dialog prompt
     alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                Log.v(TAG,"Alert Dialog cancelled when user touches outside the Dialog prompt")
            }
        });

    }


    @Override
    public void onBackPressed()
    {
    Log.v(TAG,"Back Button Pressed");
     super.onBackPressed();

     alertDialog.dismiss();   //dismiss the alertDialog
     alertPopup.this.finish();  // Destroy the current activity

     homePressed = false;
    }

    @Override
    public void onResume() {
        super.onResume();
        homePressed = true; // default: other wise onBackPressed will set it to false
    }


    @Override
    public void onPause() {
        super.onPause();
        if(homePressed) { 

        alertDialog.dismiss();   //dismiss the alertDialog
        alertPopup.this.finish();  // Destroy the current activity

        Log.v(TAG, "Home Button Pressed"); }
    }


    public void onDestroy(){

        super.onDestroy();
    }


}

Note:

Add this Permission in Android Manifest to show the alert Window .

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

Happy Coding :)

7
Eliran Kuta On

Since it's a service that hosting an overlay window, It's a bit tricky solution but it is possible.

You should handle these 2 cases separately (overriding home button press, and back button press).


1. Overriding home button press:

Create this HomeWatcher class which contains a BroadcastReceiver that will notify when home button was pressed. Register this receiver only when your window comes up.

Android: associate a method to home button of smartphone

Inside your service onCreate method use this:

HomeWatcher mHomeWatcher = new HomeWatcher(this);
mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() {
    @Override
    public void onHomePressed() {
        yourWindow.hide()  //means: windowManager.removeView(view);
    }
    @Override
    public void onHomeLongPressed() {
    }
});
mHomeWatcher.startWatch();

2. Overriding back button press:

The idea is creating an empty layout as a data member of your window class, and attach your view to it (even if its an inflated XML layout).

For example, this is gonna be your window class:

public class MyWindow
{
    private WindowManager windowManager;
    private WindowManager.LayoutParams params;
    private View view;

    // Add this empty layout:
    private MyLayout myLayout;

    public MyWindow()
    {
        windowManager = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.your_original_window_layout, null);

        // Add your original view to the new empty layout:
        myLayout = new MyLayout(this);
        myLayout.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    }

    // And show this layout instead of your original view:
    public void show()
    {
        windowManager.addView(myLayout, params);
    }

    public void hide()
    {
        windowManager.removeView(myLayout);
    }
}

And now create the MyLayout class to override the back button press:

public class MyLayout extends LinearLayout
{
    private MyWindow myWindow;

    public MyLayout(MyWindow myWindow)
    {
        super(myWindow.context);

        this.myWindow = myWindow;
    }


    @Override public boolean dispatchKeyEvent(KeyEvent event)
    {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
        {
            if (event.getAction() == KeyEvent.ACTION_DOWN  &&  event.getRepeatCount() == 0)
            {
                getKeyDispatcherState().startTracking(event, this);
                return true;

            }

            else if (event.getAction() == KeyEvent.ACTION_UP)
            {
                getKeyDispatcherState().handleUpEvent(event);

                if (event.isTracking() && !event.isCanceled())
                {
                    // dismiss your window:
                    myWindow.hide();

                    return true;
                }
            }
        }

        return super.dispatchKeyEvent(event);
    }
}

I know it's a bit complicated as I said since it's a system alert window hosted by a service, BUT it's working. I have the same issue as well and it has been solved exactly like that. Good luck.

0
Samira On

You need to overwrite the onBackPressed method.

@Override
public void onBackPressed() {

    super.onBackPressed(); // remove this if u want to handle this event
}
2
Vlad On

I understand that you are using the <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> permission for showing a floating view.

Using a floating view you can intercept the back button press, but the home button press cannot be intercepted (android won't let you primarily because of security reasons).

To intercept the back button press you need to add a wrapper when you inflate your floating view. Your wrapper should look like this:

    // Wrapper for intercepting System/Hardware key events
    ViewGroup wrapper = new FrameLayout(this) {
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
                hideAddNotesFloatingView();
                return true;
            }
            return super.dispatchKeyEvent(event);
        }
    };

Then you add it to your floating view as a root:

        mAddNoteFloatingView = mInflater.inflate(R.layout.floating_add_note, wrapper);

My complete code looks like this:

private void addFloatingView() {
    final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            0,
            PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.CENTER | Gravity.LEFT;
    params.x = 0;
    params.y = 0;

    // Wrapper for intercepting System/Hardware key events
    FrameLayout wrapper = new FrameLayout(this) {
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
                // Add your code for handling the back button press
                return true; // Return true means that the event was handled
            }
            return super.dispatchKeyEvent(event);
        }
    };

    mAddNoteFloatingView = mInflater.inflate(R.layout.floating_view, wrapper);

    mWindowManager.addView(mAddNoteFloatingView, params);
}