web-dev-qa-db-fra.com

Est-il possible de créer un service Android qui écoute les appuis matériels?

Je souhaite exécuter un service d'arrière-plan Android qui agira comme un écouteur de clé à partir de l'écran d'accueil ou lorsque le téléphone est en veille. Est-ce possible?

À partir d’exemples en ligne semi-liés, j’ai mis en place le service suivant, mais l’erreur suivante: "onKeyDown n’est pas défini pour le type Service". Cela signifie-t-il que cela ne peut être fait sans réécrire Launcher, ou y a-t-il quelque chose d'évident qui me manque?

public class ServiceName extends Service {

    @Override
    public void onCreate() {
        //Stuff
    }

    public IBinder onBind(Intent intent) {
        //Stuff
        return null;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(event.getAction() == KeyEvent.ACTION_DOWN) {
        switch(keyCode) {
        case KeyEvent.KEYCODE_A:
            //Stuff
            return true;
        case KeyEvent.KEYCODE_B:
            //Stuff
            return true;

            //etc.
        }
        }

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

Je sais que la barre de recherche s’applique par défaut à Android lorsque vous tapez à partir de l’écran d’accueil, mais c’est vraiment pour une utilisation très particulière. Je ne m'attends pas vraiment à ce que quelqu'un d'autre que moi veuille cela. Je pense simplement que ce serait bien, par exemple, d'utiliser le bouton de l'appareil photo pour réveiller le téléphone.

27
Brian

Autant que je sache, les événements KeyEvents ne peuvent être gérés que par les activités, car ils constituent l'interface avec l'utilisateur qui appuie sur les touches. Les services fonctionnent en arrière-plan et ne sont pas conçus pour réagir aux entrées de l'utilisateur. C’est aussi la raison de l’avertissement de votre compilateur "onKeyDown n’est pas défini pour le type Service". Le service ou l'une de ses superclasses n'implémente pas l'interface KeyEvent.Callback. En guise de solution de contournement, vous pouvez enregistrer une activité dans votre AndroidManifest.xml afin de réagir à certaines notifications du système, telles que Android.intent.action.SCREEN_ON. Lorsque vous appuyez sur le bouton d'alimentation pour allumer l'écran, votre activité peut être lancée, initialisez un service quelconque et revenez à l'arrière-plan. Si c'est ce que vous avez l'intention de faire. Voir Documents d'intention pour les actions possibles.

J'espère que ça a aidé ...

16
MarioB.

Cela nécessite Lollipop (v5.0/API 21) ou une version ultérieure et ne peut détecter que les clés de volume.

Elle remplacera l'action de la touche de volume, de sorte que son utilisation globale peut ne pas être souhaitée.

public class VolumeKeyController {

    private MediaSessionCompat mMediaSession;
    private final Context mContext;

    public VolumeKeyController(Context context) {
        mContext = context;
    }

    private void createMediaSession() {
        mMediaSession = new MediaSessionCompat(mContext, KeyUtil.log);

        mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mMediaSession.setPlaybackState(new Builder()
                .setState(PlaybackStateCompat.STATE_PLAYING, 0, 0)
                .build());
        mMediaSession.setPlaybackToRemote(getVolumeProvider());
        mMediaSession.setActive(true);
    }

    private VolumeProviderCompat getVolumeProvider() {
        final AudioManager audio = mContext.getSystemService(Context.AUDIO_SERVICE);

        int STREAM_TYPE = AudioManager.STREAM_MUSIC;
        int currentVolume = audio.getStreamVolume(STREAM_TYPE);
        int maxVolume = audio.getStreamMaxVolume(STREAM_TYPE);
        final int VOLUME_UP = 1;
        final int VOLUME_DOWN = -1;

        return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
            @Override
            public void onAdjustVolume(int direction) {
                // Up = 1, Down = -1, Release = 0
                // Replace with your action, if you don't want to adjust system volume
                if (direction == VOLUME_UP) {
                    audio.adjustStreamVolume(STREAM_TYPE,
                            AudioManager.ADJUST_RAISE, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
                }
                else if (direction == VOLUME_DOWN) {
                    audio.adjustStreamVolume(STREAM_TYPE,
                            AudioManager.ADJUST_LOWER, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
                }
                setCurrentVolume(audio.getStreamVolume(STREAM_TYPE));
            }
        };
    }

    // Call when control needed, add a call to constructor if needed immediately
    public void setActive(boolean active) {
        if (mMediaSession != null) {
            mMediaSession.setActive(active);
            return;
        }
        createMediaSession();
    }

    // Call from Service's onDestroy method
    public void destroy() {
        if (mMediaSession != null) {
            mMediaSession.release();
        }
    }
}
3
Gibolt

Bien qu'il ne soit pas possible d'écouter les pressions sur une touche matérielle directement dans un service, vous pouvez parfois écouter les effets de ces pressions. Par exemple, cette réponse explique comment déduire une pression sur une touche de volume à partir de modifications du volume de support.

0
Tad