Est-il possible de créer un service Android qui écoute les presses à clé matérielle?
Question
Je voudrais lancer un service d'arrière-plan Android qui agira comme keyListener de l'écran d'accueil ou lorsque le téléphone est en veille. Est-ce possible?
A partir d'exemples semi-apparentés en ligne, je mets ensemble le service suivant, mais je reçois l'erreur, « onKeyDown n'est pas défini pour le type de service ». Est-ce que cela veut dire qu'il ne peut pas se faire sans réécriture de lancement, ou est-il quelque chose d'évident, je suis absent?
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 me rends compte par défaut Android à la barre de recherche lorsque vous tapez à partir de l'écran d'accueil, mais ce qui est vraiment juste pour une utilisation très particulière. Je ne pense pas vraiment personne, mais je veux que ce. Je pense que ce serait bien, par exemple, d'utiliser le bouton de la caméra pour réveiller le téléphone.
La solution
As far as I know KeyEvents can only be handled by Activities as they are the interface to the user pressing the keys. Services run in the background and are not intended to react on user input. That's also the reason of your compiler warning "onKeyDown is undefined for the type Service". Service or any of it's Superclasses don't implement the KeyEvent.Callback interface. As a workaround you could register an Activity in your AndroidManifest.xml
to react on certain system notifications such as android.intent.action.SCREEN_ON
. When the power button is pressed to turn on the screen your activity could be started, initializing a service of some kind and go back to the background. If that's what you intend to do. See Intent docs for possible Actions.
Hope that helped...
Autres conseils
This requires Lollipop (v5.0/API 21) or higher, and can only detect volume keys
It will override volume key action, so using it globally may not be desired.
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();
}
}
}
While it is not possible to listen for hardware key presses directly in a service, you can sometimes listen for the effects of those key presses. For example, this answer describes how to infer volume key presses from changes in media volume.