OnKeyDown y onKeyLongPress

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

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

Me gustaría tener un evento o el otro, no ambos, para que pueda ajustar el volumen con una presión corta y saltear una pista con una larga presión.

¿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 se puede optimizar para una mejor lógica. Pero usted conseguirá el punto con él. La clave es usar banderas. La prensa corta es una prensa en la que pulsamos el botón de volumen durante un breve periodo de tiempo y lo soltamos . Así que 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 pulsaciones largas (no se detecta una presió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 pulsaciones 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 me enteré de que alguien ya tiene algún tipo de solución ….

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

¡Este código detecta las pulsaciones rápidas y las pulsaciones prolongadas, cuando se produce una pulsación larga, no se disparará ninguna pulsación corta!

Nota: si desea que el volumen normal de subida y bajada de comportamiento cambie el valor true en el método onKeyPress a la super llamada como esto:

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

Código sin la super 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 de aumento de volumen añadida, solo escoge 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); } 

Corregir la forma de acuerdo con el SDK para manejar pulsaciones de botón largo.

 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 de KeyDown en una base constante.

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

Para obtener los eventos de KeyDown "correctos" (los que ignoró en el paso anterior), podría tener un hilo comprobando si la diferencia de tiempo entre la hora actual del sistema y tLast (lo tDelta ) es lo suficientemente grande para que Como para no ser considerada una prensa continua.

Dado que muchos eventos KeyDown se lanzan en un corto período de tiempo, teóricamente se puede determinar que el botón de volumen no se presiona continuamente cuando los eventos están suficientemente espaciados ( tDelta es mayor que un valor fijo).

El corto plazo de esta solución es que, si el usuario presiona el botón de volumen muy rápido ( tDelta entre las prensas es menor que el valor fijo usado para evaluar una prensa continua), las múltiples pulsaciones de teclas serán ignoradas / consideradas como una tecla continua prensa.

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

Saludos,

Lucian

EDIT: Hmm … pensamiento en segundo lugar: ¿No está utilizando una implementación de KeyListener Android?

Si está utilizando esto, echa un vistazo al método onKeyUp definido para esto.

Creo que sería más elegante si sólo ampliar esta clase (o una de las clases derivadas) y utilizar el método onKeyUp para determinar si se trata de una prensa continua (es decir, el tiempo que el botón se ha mantenido presionado es mayor Que un valor fijo).

Si puede utilizar este método, por favor, hágalo. También es más eficiente, más fácil de mantener y más sencillo que el trabajo descrito anteriormente.

KeyListener Javadoc

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.