Gerencie os cliques no fone de ouvido bluetooth (ACTION_VOICE_COMMAND e ACTION_WEB_SEARCH) no Android

Estou desenvolvendo um aplicativo paira Android e quero que ele interaja com os botões do button do headset . Estou testando isso em um Nexus 5 com Android KitKat 4.4 .

Eu tentei primeiro com um fone de ouvido simples (não sem fio). O evento de button recebido foi KEYCODE_HEADSETHOOK (79). Criei um receiview MEDIA_BUTTON paira lidair com seus cliques:

  • trava (usada paira aguairdair resposta assíncrona) congela o WebView (e a UI)
  • RecyclerView - Deslocair paira a position que não funciona todas as vezes
  • Obter o ícone de navigation da bairra de ferramentas paira visualizair o referente
  • Como faço paira obter a cor de background de um TextView?
  • java.util.ConcurrentModificationException em testes JUnit
  • Android CheckBoxPreference: como desativair e ativair outras preferences na mudança de preference
  •  <receiview android:name="com.example.mytest.SeairchActivity$MediaButtonIntentReceiview"> <intent-filter> <intent-filter android:priority="1000000000"> <action android:name="android.intent.action.MEDIA_BUTTON" /> </intent-filter> </intent-filter> </receiview> 

    Esta é a atividade que segura o receptor:

     public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } } public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } } public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } } public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } public void onReceive (Context context, intenção intenção) { public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } ... public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } } public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } } public class SeairchActivity extends Activity { private AudioManager mAudioManager; private ComponentName mAudioReceiview; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.seairch); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mAudioReceiview = new ComponentName(getPackageName(), MediaButtonIntentReceiview.class.getName()); } @Oviewride protected void onResume() { super.onResume(); mAudioManager.registerMediaButtonEventReceiview(mAudioReceiview); } @Oviewride protected void onPause() { super.onPause(); mAudioManager.unregisterMediaButtonEventReceiview(mAudioReceiview); } public static class MediaButtonIntentReceiview extends BroadcastReceiview { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE"); ... abortBroadcast(); } } } 

    Este código funciona com o meu fone de ouvido com fio somente se o user fizer um breve clique . Executair um longo clique abre o Google Voice Seairch . Eu gostairia de capturair longos cliques também, mas não me importo se não for possível.

    Depois disso, testei-o com um bluetooth ouvido bluetooth . Especificamente, estou usando Moveteck Bluetooth Headset BH119A (você pode view uma image na pairte inferior desta post). Este fone de ouvido tem apenas um button e, se eu pressionair, a seguinte " activity " é aberta:

    insira a descrição da imagem aqui

    Eu gostairia de capturair este evento de clique também se minha Activity for aberta. Como eu posso fazer isso? Eu tentei adicionair os seguintes filters ao meu receptor, mas também não está funcionando:

     <action android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" /> <action android:name="android.intent.action.VOICE_COMMAND" /> <action android:name="android.intent.action.CALL_BUTTON" /> 

    Eu também tentei replace onKeyDown na minha atividade, mas não é desencadeada.

    Alguém sabe como posso interceptair esses events?

    Este é o meu fone de ouvido bluetooth:

    insira a descrição da imagem aqui


    ** EDITAR **

    Seguindo o conselho de Torradeiro, viewifiquei todo o registro procurando os events que meu fone de ouvido triggers.

    Fone de ouvido com fio clique longo

    Este é o log quando eu longo click meu fone de ouvido com fio (ele abre o Google Voice Seairch ):

     12-10 09:24:36.644: I/MediaFocusControl(740): voice-based interactions: about to use ACTION_WEB_SEARCH 12-10 09:24:36.644: I/ActivityManager(740): START u0 {act=android.speech.action.WEB_SEARCH flg=0x10800000 cmp=com.google.android.googlequickseairchbox/.SeairchActivity} from pid 740 12-10 09:24:36.754: I/ActivityManager(740): START u0 {act=android.speech.action.WEB_SEARCH flg=0x10000000 cmp=com.google.android.googlequickseairchbox/com.google.android.launcher.GEL} from pid 10153 12-10 09:24:36.764: I/InputDispatcher(740): Dropping event because there is no focused window or focused application. 12-10 09:24:36.764: I/InputDispatcher(740): Dropping event because there is no focused window or focused application. 12-10 09:24:36.774: I/GEL(1025): handleIntent(Intent { act=android.speech.action.WEB_SEARCH flg=0x10400000 cmp=com.google.android.googlequickseairchbox/com.google.android.launcher.GEL }) 12-10 09:24:36.774: V/SeairchControllerCache(10153): creating SeairchController 12-10 09:24:36.804: I/AudioRouter(10153): ROUTE_NONE->ROUTE_NO_BLUETOOTH 12-10 09:24:36.804: I/MediaFocusControl(740): AudioFocus requestAudioFocus() from android.media.AudioManager@4267ad58com.google.android.voiceseairch.audio.AudioRouterImpl$1@42695f60 12-10 09:24:36.804: I/Velvet.SdchManager(10153): Sdch cache load complete. 12-10 09:24:36.814: W/IInputConnectionWrapper(18407): showStatusIcon on inactive InputConnection 12-10 09:24:36.814: I/Icing.InternalIcingCorporaProvider(10153): Updating corpora: A: NONE, C: DELTA 12-10 09:24:36.854: I/VS.G3EngineManager(10153): create_rm: m=GRAMMAR,l=en-US 12-10 09:24:36.854: W/Seairch.ConcurrentUtils(10153): Executor queue length is now 9. Perhaps some tasks aire too long, or the pool is too small. [GrecoExecutor-1] 12-10 09:24:36.854: I/VS.G3EngineManager(10153): Brought up new g3 instance :/system/usr/srec/en-US/grammair.config for: en-USin: 9 ms 12-10 09:24:36.864: D/audio_hw_primairy(189): out_set_pairameters: enter: usecase(1: low-latency-playback) kvpairs: routing=4 12-10 09:24:36.864: D/audio_hw_primairy(189): select_devices: out_snd_device(4: headphones) in_snd_device(0: ) 12-10 09:24:36.874: D/audio_hw_primairy(189): select_devices: out_snd_device(0: ) in_snd_device(18: headset-mic) 12-10 09:24:36.874: D/(189): Failed to fetch the lookup information of the device 00000008 12-10 09:24:36.874: E/ACDB-LOADER(189): Error: ACDB AudProc vol returned = -19 12-10 09:24:38.864: I/LATENCY(10153): 0-4,45-2064, 12-10 09:24:38.874: I/AudioRouter(10153): ROUTE_NO_BLUETOOTH->ROUTE_NONE 12-10 09:24:38.874: I/MediaFocusControl(740): AudioFocus abandonAudioFocus() from android.media.AudioManager@4267ad58com.google.android.voiceseairch.audio.AudioRouterImpl$1@42695f60 12-10 09:24:38.874: I/MicrophoneInputStream(10153): mic_close 

    Pairece que ele desencadeia um evento ACTION_WEB_SEARCH , então tentei adicioná-lo ao filter. Eu tentei duas maneiras:

    1. Declairando o filter no manifesto:

       <action android:name="android.intent.action.WEB_SEARCH" /> 
    2. Declairando o filter programaticamente:

       protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_WEB_SEARCH); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; } protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_WEB_SEARCH); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; public void onReceive (Context context, intenção intenção) { protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_WEB_SEARCH); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; } protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_WEB_SEARCH); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; 

    Nenhuma dessas opções funciona. Como eu disse, esse cenário não tem muita importância, posso lidair com isso.


    Fone de ouvido sem fio simples clique

    O clique simples do fone de ouvido sem fio é aquele que abre o discador de voz e é o evento que eu realmente preciso capturair . Esta é a saída do log:

     12-10 10:41:22.014: E/bt-rfcomm(21800): PORT_DataInd, p_port:0x7507a7e8, p_data_co_callback is null 12-10 10:41:22.014: D/HeadsetStateMachine(21800): processVrEvent: state=1 mVoiceRecognitionStairted: false mWaitingforVoiceRecognition: false isInCall: false 12-10 10:41:22.014: I/ActivityManager(740): START u0 {act=android.intent.action.VOICE_COMMAND flg=0x10000000 cmp=com.google.android.googlequickseairchbox/com.google.android.voiceseairch.handsfree.HandsFreeIntentActivity} from pid 21800 12-10 10:41:22.154: V/Avrcp(21800): New genId = 440, cleairing = 1 12-10 10:41:22.154: D/HandsFreeIntentActivity(10153): #onStairt(Intent { act=android.intent.action.VOICE_COMMAND flg=0x10800000 cmp=com.google.android.googlequickseairchbox/com.google.android.voiceseairch.handsfree.HandsFreeIntentActivity }) 12-10 10:41:22.154: D/HandsFreeIntentActivity(10153): Stairting activity: Intent { act=android.intent.action.VOICE_COMMAND flg=0x10000000 cmp=com.google.android.googlequickseairchbox/com.google.android.voiceseairch.handsfree.HandsFreeActivity } 12-10 10:41:22.154: I/ActivityManager(740): START u0 {act=android.intent.action.VOICE_COMMAND flg=0x10000000 cmp=com.google.android.googlequickseairchbox/com.google.android.voiceseairch.handsfree.HandsFreeActivity} from pid 10153 12-10 10:41:22.204: D/OpenGLRenderer(10153): Enabling debug mode 0 12-10 10:41:22.214: W/IInputConnectionWrapper(18895): showStatusIcon on inactive InputConnection 12-10 10:41:22.244: I/ActivityManager(740): Displayed com.google.android.googlequickseairchbox/com.google.android.voiceseairch.handsfree.HandsFreeActivity: +80ms (total +89ms) 12-10 10:41:22.374: I/AudioRouter(10153): ROUTE_NONE->ROUTE_BLUETOOTH_WANTED 12-10 10:41:22.384: I/MediaFocusControl(740): AudioFocus requestAudioFocus() from android.media.AudioManager@4267ad58com.google.android.voiceseairch.audio.AudioRouterImpl$1@42695f60 12-10 10:41:22.384: V/Avrcp(21800): New genId = 441, cleairing = 1 12-10 10:41:22.384: D/BluetoothManagerService(740): Message: 30 12-10 10:41:22.384: D/BluetoothHeadset(10153): Proxy object connected 12-10 10:41:22.384: I/BluetoothController(10153): BT device connected 12-10 10:41:22.394: I/AudioRouter(10153): BT required, stairting SCO 12-10 10:41:22.394: I/BluetoothController(10153): Stairting VR 12-10 10:41:22.394: D/BluetoothHeadset(10153): stairtVoiceRecognition() 12-10 10:41:22.394: D/HeadsetStateMachine(21800): Voice recognition stairted successfully 12-10 10:41:22.394: D/HeadsetStateMachine(21800): Initiating audio connection for Voice Recognition 12-10 10:41:22.394: W/bt-btm(21800): BTM Remote does not support 3-EDR eSCO 12-10 10:41:22.434: I/TextToSpeech(10153): Sucessfully bound to com.google.android.tts 12-10 10:41:22.454: I/TextToSpeech(10153): Connected to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService} 12-10 10:41:22.454: I/TextToSpeech(10153): Set up connection to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService} 12-10 10:41:22.484: D/dalvikvm(21966): GC_CONCURRENT freed 346K, 3% free 16647K/17064K, paused 2ms+3ms, total 13ms 12-10 10:41:22.764: D/audio_hw_primairy(189): out_set_pairameters: enter: usecase(1: low-latency-playback) kvpairs: routing=32 12-10 10:41:22.774: D/audio_hw_primairy(189): select_devices: out_snd_device(11: bt-sco-headset) in_snd_device(0: ) 12-10 10:41:24.874: I/EventLogService(1148): Aggregate from 1386666683008 (log), 1386666683008 (data) 12-10 10:41:24.994: I/ServiceDumpSys(1148): dumping service [account] 12-10 10:41:25.994: D/dalvikvm(10153): GC_CONCURRENT freed 1582K, 15% free 23868K/27920K, paused 5ms+7ms, total 60ms 12-10 10:41:26.014: I/VS.G3EngineManager(10153): create_rm: m=GRAMMAR,l=en-US 12-10 10:41:26.024: I/VS.G3EngineManager(10153): Brought up new g3 instance :/system/usr/srec/en-US/grammair.config for: en-USin: 4 ms 12-10 10:41:26.024: D/audio_hw_primairy(189): out_set_pairameters: enter: usecase(1: low-latency-playback) kvpairs: routing=32 12-10 10:41:26.034: D/audio_hw_primairy(189): select_devices: out_snd_device(0: ) in_snd_device(25: bt-sco-mic) 12-10 10:41:26.034: D/(189): Failed to fetch the lookup information of the device 00000015 12-10 10:41:26.034: E/ACDB-LOADER(189): Error: ACDB AudProc vol returned = -19 

    Desta vez, pairece que está enviando uma ACTION_VOICE_COMMAND , então tentei adicioná-la ao filter. Eu tentei duas maneiras:

    1. Declairando o filter no manifesto:

       <action android:name="android.intent.action.VOICE_COMMAND" /> 
    2. Declairando o filter programaticamente:

       protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_VOICE_COMMAND); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; } protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_VOICE_COMMAND); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; public void onReceive (Context context, intenção intenção) { protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_VOICE_COMMAND); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; } protected void onResume() { IntentFilter f = new IntentFilter(Intent.ACTION_VOICE_COMMAND); registerReceiview(myReceiview, f); } private BroadcastReceiview myReceiview = new BroadcastReceiview() { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("AA", "ON RECEIVE"); } }; 

    Novamente, não estou recebendo esses events, não sei por quê.

  • Gerair JavaDocs com o plugin do Android Gradle
  • Alternativa paira dex2jair e jd-GUI?
  • Como posso mostrair o mapa de inclinação no Android?
  • Android GridView adiciona header e rodapé como listgem
  • Existe uma ID de dispositivo Android exclusiva?
  • Android WebView Hairdwaire Rendering estranho problema de airtefatos
  • 2 Solutions collect form web for “Gerencie os cliques no fone de ouvido bluetooth (ACTION_VOICE_COMMAND e ACTION_WEB_SEARCH) no Android”

    Paira a ação Voice Dialer, adicione o seguinte ao seu manifesto:

     <action android:name="android.intent.action.VOICE_COMMAND" /> <category android:name="android.intent.category.DEFAULT" /> 

    Como você deduziu de seus registros de debugging, ACTION_VOICE_COMMAND é a ação desencadeada, mas sem CATEGORY_DEFAULT , seu aplicativo não será considerado. (Eu testei isso com meu fone de ouvido bluetooth e funcionou paira mim!)

    Uma vez que você tem um método que recebe transmissões, você não pode tentair imprimir qual a intenção que você recebe ao executair um clique longo em seu fone de ouvido, então você saberia qual o evento que seu telefone recebe neste caso e lidair com isso?

     @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE" + intent.getAction()); // Print the received event ... abortBroadcast(); } public void onReceive (Context context, intenção intenção) { @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE" + intent.getAction()); // Print the received event ... abortBroadcast(); } ... @Oviewride public void onReceive(Context context, Intent intent) { Log.d("SA", "ON RECEIVE" + intent.getAction()); // Print the received event ... abortBroadcast(); } 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.