Мне нужно закрыть окно системного оповещения при нажатии кнопки back
и нажатии кнопки home
. Я пробовал с onKeyEvent
, но тщетно. Поскольку мы не можем зафиксировать событие back
press в службе, как этого добиться?
Назад нажатые события с окном системного предупреждения
Ответы (10)
Поскольку это служба, в которой размещается оверлейное окно, это немного сложное решение, но оно возможно.
Вы должны обрабатывать эти 2 случая отдельно (переопределение нажатия кнопки «Домой» и нажатия кнопки «Назад»).
<сильный>1. Переопределение нажатия кнопки "Домой":
Создайте этот класс HomeWatcher, который содержит BroadcastReceiver, который будет уведомлять о нажатии кнопки «Домой». Зарегистрируйте этот приемник только тогда, когда появится ваше окно.
Android: привязать метод к домашней кнопке смартфона
Внутри вашего метода onCreate службы используйте это:
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. Отмена нажатия кнопки «Назад»:
Идея состоит в том, чтобы создать пустой макет в качестве члена данных вашего класса окна и прикрепить к нему свое представление (даже если это раздутый XML-макет).
Например, это будет ваш класс окна:
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);
}
}
А теперь создайте класс MyLayout, чтобы переопределить нажатие кнопки «Назад»:
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);
}
}
Я знаю, что это немного сложно, как я уже сказал, поскольку это окно системного предупреждения, размещенное службой, НО оно работает. У меня такая же проблема, и она решена точно так же. Удачи.
используйте приведенный ниже метод для обработки нажатия кнопки «Назад».
public void onBackPressed()
{
super.onBackPressed();
}
Вам нужно перезаписать метод onBackPressed
.
@Override
public void onBackPressed() {
super.onBackPressed(); // remove this if u want to handle this event
}
Используйте код ниже
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();
}
@Override
public void onBackPressed()
{
super.onBackPressed();
}
Заявите об этом в своей деятельности. super.OnBackPressed автоматически вызывает метод обратного вызова в android. это обязательно отменит ваш диалог.
кроме того, ваш диалог должен выглядеть так.
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();
или вы можете установить кнопку «Отрицательный»..
Надеюсь это поможет!
Определите пользовательский макет и переопределите dispatchKeyEvent
, например:
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);
}
}
Затем добавьте представление с помощью этого кода:
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);
Когда вы нажмете кнопку «Назад», вид исчезнет.
WindowManager.LayoutParams
?
- person Mattia Maestrini; 05.11.2015
- Покажите окно предупреждения через действие, чтобы вы могли его обнаружить.
Реализуйте код для легкого обнаружения нажатия кнопки «Назад» или кнопки «Домой».
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();
}
}
Примечание:
Добавьте это разрешение в манифест Android, чтобы показать окно предупреждения.
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Удачного кодирования :)
Насколько я понимаю, вы используете разрешение <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
для отображения плавающего представления.
Используя плавающий вид, вы можете перехватить нажатие кнопки back
, но нажатие кнопки home
не может быть перехвачено (Android не позволит вам в первую очередь из соображений безопасности).
Чтобы перехватить нажатие кнопки back
, вам нужно добавить обертку, когда вы раздуваете свой плавающий вид. Ваша обертка должна выглядеть так:
// 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);
}
};
Затем вы добавляете его в свой плавающий вид как корень:
mAddNoteFloatingView = mInflater.inflate(R.layout.floating_add_note, wrapper);
Мой полный код выглядит так:
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);
}
mAddNoteFloatingView
и wrapper
относятся к одному и тому же представлению. LayoutInflater.inflate
возвращает: корневое представление раздутой иерархии. Если был указан корень, это корневой вид; в противном случае это корень раздутого XML-файла.
- person Vlad; 25.05.2017
Это просто. Следуй этим шагам:
- Создайте представление, такое как относительный макет, линейный макет или динамический макет кадра. 2. Переопределите
dispatchKeyEvent
при создании представления. - Добавьте свое исходное представление в это динамически созданное представление с помощью метода
addView()
. - Добавьте динамически созданный вид в свой оконный менеджер или диалоговое окно предупреждений в зависимости от того, что вы хотите.
В дополнение к решению @Eliran Kuta, это более простой ответ для кнопки «Назад».
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)