onKeyDown y onKeyLongPress

Quiero que mi aplicación reaccione de manera diferente a un evento clave normal y prolongado de los botones de volumen.

Ya he visto esto , pero si mantengo presionado el botón de volumen, recibo muchos eventos KeyDown antes de obtener el evento KeyLongPressed .

Me gustaría tener un evento u otro, no ambos, para poder ajustar el volumen con una pulsación corta y saltar una pista con una pulsación larga.

¿Me puede ayudar aquí?

Este es mi código:

  @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { Log.d("Test", "Long press!"); return true; } return super.onKeyLongPress(keyCode, event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { event.startTracking(); Log.d("Test", "Short"); return true; } return super.onKeyDown(keyCode, event); } 

Cualquier ayuda apreciada! – Iris

Aquí está el código que escribí. Funciona a las mil maravillas. Puede ser que puedas optimizarlo para una mejor lógica. Pero obtendrá el punto con eso. La clave es usar banderas. Pulsación corta es una prensa donde presionamos el botón de volumen por un tiempo breve y lo lanzamos . Entonces onKeyUp es el que nos ayudará a detectar presiones cortas.

 package com.example.demo; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; public class TestVolumeActivity extends Activity { boolean flag = false; boolean flag2 = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash_screen); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_splash_screen, menu); return true; } @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { Log.d("Test", "Long press!"); flag = false; flag2 = true; return true; } return super.onKeyLongPress(keyCode, event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { event.startTracking(); if (flag2 == true) { flag = false; } else { flag = true; flag2 = false; } return true; } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { event.startTracking(); if (flag) { Log.d("Test", "Short"); } flag = true; flag2 = false; return true; } return super.onKeyUp(keyCode, event); } } 

Logcat para todas las prensas largas (no se ha detectado una pulsación corta):

 10-18 02:06:15.369: D/Test(16834): Long press! 10-18 02:06:18.683: D/Test(16834): Long press! 10-18 02:06:21.566: D/Test(16834): Long press! 10-18 02:06:23.738: D/Test(16834): Long press! 

Logcat para todas las prensas cortas:

 10-18 02:07:42.422: D/Test(16834): Short 10-18 02:07:43.203: D/Test(16834): Short 10-18 02:07:43.663: D/Test(16834): Short 10-18 02:07:44.144: D/Test(16834): Short 

Cuando estaba a punto de publicar mi respuesta, descubrí que alguien ya tenía algún tipo de solución …

Pero aquí está el mío, simple y funciona como un encanto. Solo una bandera;)

Este código detecta las pulsaciones cortas y las pulsaciones largas, cuando se produce una pulsación larga, ¡no se activará la pulsación corta!

Nota: si desea que el volumen normal suba y baje el comportamiento, cambie la respuesta true en el método onKeyPress a la súper llamada como esta:

 event.startTracking(); if(event.getRepeatCount() == 0){ shortPress = true; } //return true; return super.onKeyDown(keyCode, event); 

Código sin la súper llamada:

 private boolean shortPress = false; @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { shortPress = false; Toast.makeText(this, "longPress", Toast.LENGTH_LONG).show(); return true; } //Just return false because the super call does always the same (returning false) return false; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { if(event.getAction() == KeyEvent.ACTION_DOWN){ event.startTracking(); if(event.getRepeatCount() == 0){ shortPress = true; } return true; } } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { if(shortPress){ Toast.makeText(this, "shortPress", Toast.LENGTH_LONG).show(); } else { //Don't handle longpress here, because the user will have to get his finger back up first } shortPress = false; return true; } return super.onKeyUp(keyCode, event); } 

El código aquí abajo es con la tecla para subir el volumen, simplemente elige tu lado;)

 private boolean shortPress = false; @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { shortPress = false; Toast.makeText(this, "longPress Volume Down", Toast.LENGTH_LONG).show(); return true; } else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP){ shortPress = false; Toast.makeText(this, "longPress Volume Up", Toast.LENGTH_LONG).show(); return true; } //Just return false because the super call does always the same (returning false) return false; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) { if(event.getAction() == KeyEvent.ACTION_DOWN){ event.startTracking(); if(event.getRepeatCount() == 0){ shortPress = true; } return true; } } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { if(shortPress){ Toast.makeText(this, "shortPress Volume Down", Toast.LENGTH_LONG).show(); } else { //Don't handle longpress here, because the user will have to get his finger back up first } shortPress = false; return true; } else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP){ if(shortPress){ Toast.makeText(this, "shortPress Volume up", Toast.LENGTH_LONG).show(); } else { //Don't handle longpress here, because the user will have to get his finger back up first } shortPress = false; return true; } return super.onKeyUp(keyCode, event); } 

Forma correcta de acuerdo con el SDK para manejar pulsaciones de botón largas.

 import android.app.Activity; import android.util.Log; import android.view.KeyEvent; public class TestVolumeActivity extends Activity { private static final String TAG = TestVolumeActivity.class.getSimpleName(); @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if( keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { event.startTracking(); return true; } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_VOLUME_UP){ Log.d(TAG, "Long press KEYCODE_VOLUME_UP"); return true; } else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){ Log.d(TAG, "Long press KEYCODE_VOLUME_DOWN"); return true; } return super.onKeyLongPress(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if((event.getFlags() & KeyEvent.FLAG_CANCELED_LONG_PRESS) == 0){ if(keyCode == KeyEvent.KEYCODE_VOLUME_UP){ Log.e(TAG, "Short press KEYCODE_VOLUME_UP"); return true; } else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){ Log.e(TAG, "Short press KEYCODE_VOLUME_DOWN"); return true; } } return super.onKeyUp(keyCode, event); } } 

No sé si esta respuesta proporcionará una solución aceptable a su problema, ya que se ha KeyDown en obtener frecuentes eventos KeyDown de manera constante.

Podría intentar recordar la hora del sistema cuando se lanza el último evento KeyDown (lo llamaré tLast ) e ignorar todos los eventos KeyDown hasta que obtenga un evento KeyLongPressed .

Para obtener los eventos KeyDown “correctos” (los que ignoró en el paso anterior), podría tener una verificación de hilos si la diferencia de tiempo entre la hora actual del sistema y tLast (lo llamaré tDelta ) es lo suficientemente grande para como no ser considerado una prensa continua.

Dado que muchos eventos de KeyDown se lanzan en un corto período de tiempo, en teoría podría determinar si el botón de volumen no se presionó de manera continua cuando los eventos están lo suficientemente espaciados ( tDelta es mayor que un valor fijo).

El tDelta de esta solución es que, si el usuario presiona el botón de volumen muy rápido ( tDelta entre pulsaciones es menor que el valor fijo utilizado para evaluar una pulsación continua), las pulsaciones de teclas múltiples se ignorarán / considerarán como una tecla continua prensa.

Otro (menor) tDelta es que habría un retraso antes de interpretar las pulsaciones de teclas normales, ya que tDelta debería ser mayor que el valor fijo utilizado al evaluar si se trata de una pulsación de tecla regular o continua.

Saludos,

Lucian

EDITAR: Mmm … pensándolo bien: ¿No estás usando una implementación de KeyListener Android?

Si está utilizando esto, consulte el método onKeyUp definido para esto.

Creo que sería más elegante si solo extendieras esta clase (o una de sus clases derivadas) y usas el método onKeyUp para determinar si estás lidiando con una presión continua (es decir, el tiempo que el botón se mantiene presionado es mayor que un valor fijo).

Si puede usar este método, hágalo. También es más eficiente, más fácil de mantener y más sencillo que el trabajo alternativo presentado anteriormente.

KeyListener Javadoc