Переопределить кнопку питания, как кнопка "Домой"

Что ж, я делаю что-то, в чем я хочу отключить все жесткие кнопки устройства.

Жесткие кнопки, такие как Power, Home, Volume up, Volume down, Search, Back.

Я успешно переопределил здесь почти все кнопки, кроме Power.

Поэтому я просто хочу, чтобы вы, люди, увидели и поделились некоторыми идеями, чтобы я мог с этим справиться.

Я получаю долгое нажатие Power keyevent в onDispatchKeyEvent() Точно так же я хочу поймать короткий щелчок того же. Кроме того, при нажатии кнопки питания я также пытался отключить экран, получая Broadcast из SCREEN_OFF и мне удалось получить его, но я не смог справиться с этим.

Благодарю.

Затем я создал ReceiverScreen, который получает трансляцию экрана вкл / выкл

ReceiverScreen.java

public class ReceiverScreen extends BroadcastReceiver {

    public static boolean wasScreenOn = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            // do whatever you need to do here
            wasScreenOn = false;
        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            // and do whatever you need to do here
            wasScreenOn = true;
        }
    }
}

DisableHardButton.java

public class DisableHardButton extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);
    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    BroadcastReceiver mReceiver = new ReceiverScreen();
    registerReceiver(mReceiver, filter);
    }

@Override
    protected void onPause() {
        // when the screen is about to turn off
        if (ScreenReceiver.wasScreenOn) {
            // this is the case when onPause() is called by the system due to a screen state change
            System.out.println("SCREEN TURNED OFF");

    } else {
        // this is when onPause() is called when the screen state has not changed
    }
    super.onPause();
}

@Override
protected void onResume() {
    // only when screen turns on
    if (!ScreenReceiver.wasScreenOn) {
        // this is when onResume() is called due to a screen state change
        System.out.println("SCREEN TURNED ON");
    } else {
        // this is when onResume() is called when the screen state has not changed
    }
    super.onResume();
}
}

6 ответов

Решение

Уф. Это довольно спорный вопрос, за которым стоит множество комментариев.

Позвольте мне начать с перефразирования вашего вопроса. Если я правильно понимаю, вы хотели бы отключить все физические кнопки на устройстве на время вашей активности. Это включает кнопку питания, которую вы обнаруживаете, обращаясь с ACTION_SCREEN_OFF намерение. Ваш текущий (успешный) обходной путь для этого сценария заключается в трансляции ACTION_SCREEN_ONвозвращая экран к жизни, когда он выключен, при условии, что хост реализует это правильно.

Теперь вы хотели бы пройти лишнюю милю, сделав это действие ненужным, если (и только если) вы сможете поймать и обработать ACTION_SCREEN_OFF прежде чем он будет отправлен в систему. Возможно ли это, и если да, то как?

Это вызывает некоторое обсуждение. Короткая версия, однако, проста: это невозможно без специального изменения прошивки или ядра операционной системы Android для ограниченного числа устройств.

Система Android, насколько это задокументировано, определяет это как действие трансляции. Следуя шаблону публикации-подписки при распространении сообщений, это сообщение будет уведомлять все заинтересованные стороны об этом действии. Поскольку это сообщение отправляется системой, поскольку стек сообщений управляется системой, а также потому, что сообщение также принимается системой, ваш код просто не вводится в нужном месте, чтобы заблокировать прием этого сообщения.

Кроме того, для некоторых устройств это будет физический коммутатор, который не имеет никакого программного прерывания. В лучшем случае система Android может рассчитывать на событие, когда это происходит, именно поэтому это широковещательное сообщение является чем-то особенным в стеке услуг. Насколько я знаю и основываясь на редкой документации по этому сценарию, вот почему это не стандартная поддерживаемая функция, прежде чем мы рассмотрим любой из возможных векторов злоупотребления.

Ваш лучший выход на самом деле гораздо проще, если у вас есть возможность изменить физическое оборудование для рассматриваемого устройства: ограничить доступ, отключить или иным образом отключить кнопку физического питания. Во многих сценариях это нежелательно, но это работает в ситуациях, когда ваше устройство Android используется, например, в качестве торгового центра или машины общего обслуживания. Если это нереализуемо, все, что требуется, это наложить физические ограничения на доступ к кнопке питания, обрабатывая оставшиеся случаи (например, точечные попытки переключения на экран), отправив ACTION_SCREEN_ON,

Просто помните, что эта стратегия не является надежной. Делайте это грамотно и хорошо документируйте процедуру, чтобы не стать кормом для следующего 2600 разоблачений.

Желаем удачи в вашем приложении.

Напротив на все ответы.. Проверьте это:


@Override
public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
                Log.i("", "Dispath event power");
                Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
                sendBroadcast(closeDialog);
                return true;
        }

        return super.dispatchKeyEvent(event);
}

Что оно делает:

Всякий раз, когда пользователь нажимает кнопку питания. Мы отменяем диалог еще до того, как его увидим!!:) Это работает для меня.. (проверено на note2)

Вот что я сделал:

(1) Создайте класс получателя:

public class ScreenReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        switch (action) {
            case Intent.ACTION_SCREEN_OFF:
                BaseActivity.unlockScreen();
                break;

            case Intent.ACTION_SCREEN_ON:
                // and do whatever you need to do here
                BaseActivity.clearScreen();
        }
    }
}

(2) Два метода, которые вызываются выше, выглядят так:

public static void unlockScreen () {
    if (current == null) return;

    Log.i( Constants.TAG, "Turning on screen ... " );

    Window window = current.getWindow();
    window.addFlags( WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD );
    window.addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED );
    window.addFlags( WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON   );
}

public static void clearScreen () {
    if (current == null) return;

    Log.i( Constants.TAG, "Clearing screen flag when on ... " );

    Window window = current.getWindow();
    window.clearFlags( WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD );
    window.clearFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED );
    window.clearFlags( WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON   );
}

private static BaseActivity current;

@Override
protected void onResume () {
    current = this;
}

(3) В методе onCreate() основного класса активности зарегистрируйте получателя:

    IntentFilter filter = new IntentFilter( Intent.ACTION_SCREEN_ON );
    filter.addAction( Intent.ACTION_SCREEN_OFF );
    registerReceiver(new ScreenReceiver(), filter);

Вы можете узнать о нажатии кнопки питания, но я не думаю, что вы сможете переопределить его, и вы сможете закрыть диалоговое окно для отключения питания и показать что-то еще.

Вот что я пробовал,

package com.easylogs.app;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
    public void onReceive(final Context context, final Intent intent) {
        Log.i("HERE", "------------------------------------HERE");
        Toast.makeText(context, "OFFFFFFFFFFFFFFFF",Toast.LENGTH_LONG).show();
    }
}

и декларация в Манифесте как,

    <receiver android:name="CloseSystemDialogsIntentReceiver">
    <intent-filter>
            <action android:name="android.intent.action.CLOSE_SYSTEM_DIALOGS" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>

Я знаю, что это слишком поздно, но может быть полезно для других разработчиков в будущем. Проверено на Android N. Ссылка с /questions/23689472/kak-ya-mogu-pojmat-knopku-pitaniya-dlitelnoe-nazhatie/23689480#23689480

 @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(!hasFocus) {
           Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            sendBroadcast(closeDialog);
        }
    }
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {

        return true;
    }

    return super.dispatchKeyEvent(event);
}

Вы пробовали приведенный выше код, где мы можем обработать событие клавиши питания. Также взгляните на эту ССЫЛКУ, которая обрабатывает событие нажатия кнопки питания.

Если кто-то ищет решение для превращения вашего приложения в режим киоска /COSU(корпоративное одноразовое приложение), где вам нужно отключить различные аппаратные кнопки, перейдите по ссылке ниже -

https://www.andreasschrade.com/2015/02/16/android-tutorial-how-to-create-a-kiosk-mode-in-android/

Другие вопросы по тегам