android 耳机按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
                                                                                                                                转载请注明出处:http://blog.csdn.net/qinjuning
  
  
            在Android中并没有定义MediaButtonReceive这个广播类,MediaButtonReceive只是作为一种通俗的命名方式来响应
   插入耳机后,点击耳机上的按钮(名称:MEDIA_BUTTON)接受该广播事件的类。所有该MEDIA_BUTTON的按下我们就简称
   为MEDIA_BUTTON广播吧。
            
           顾名思义:它显然是一个广播接收器类(BroadbcastReceiver),那么它就具备了BroadbcastReceiver类的使用方式,
   但是,因为它需要通过AudioManager对象注册,所以它有着自己的独特之处(否则我也不会单独拿出来分析,- -),后面我们
   会慢慢的讲解。
  
        点击MEDIA_BUTTON发送的Intent Action 为:
                        ACTION_MEDIA_BUTTON  ="android.intent.action.MEDIA_BUTTON"
  
        Intent 附加值为(Extra)点击MEDIA_BUTTON的按键码 :   
                        //获得KeyEvent对象
                        KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
                        //获得Action
                        String intentAction = intent.getAction() ;
  
AudioManager对象注册MEDIA_BUTTON广播的方法原型为:
  
   public voidregisterMediaButtonEventReceiver(ComponentNameeventReceiver)
          Register a component to be the sole receiverof MEDIA_BUTTON intents
          Parameters:                  
                eventReceiver  : identifier of a BroadcastReceiver that will receive the media button intent. This broadcast receiver
                                   must be declared in the application manifest.
   从注释可知以下两点:
      1、 在AudioManager对象注册一个MediaoButtonRecevie,使它成为MEDIA_BUTTON的唯一接收器(这很重要,
          我们会放在后面讲解)   也就是说只有我能收到,其他的都收不到这个广播了,否则的话大家都收到会照成一定的混乱;
      2、   该广播必须在AndroidManifest.xml文件中进行声明,否则就监听不到该MEDIA_BUTTON广播了。
  
下面我们就简单的写一个MediaButtonReceiver类,并且在AndroidManifest.xml定义
  
1、  自定义的MediaButtonReceiver 广播类
[java] view plaincopyprint?
package com.qin.mediabutton; 
   
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.util.Log; 
import android.view.KeyEvent; 
   
public class MediaButtonReceiver extends BroadcastReceiver { 
    private static String TAG = "MediaButtonReceiver"
    @Override 
    public void onReceive(Context context, Intent intent) { 
        // 获得Action 
        String intentAction = intent.getAction(); 
        // 获得KeyEvent对象 
        KeyEvent keyEvent = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 
   
        Log.i(TAG, "Action ---->" + intentAction + "  KeyEvent----->"+ keyEvent.toString()); 
   
        if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { 
            // 获得按键字节码 
            int keyCode = keyEvent.getKeyCode(); 
            // 按下 / 松开 按钮 
            int keyAction = keyEvent.getAction(); 
            // 获得事件的时间 
            long downtime = keyEvent.getEventTime(); 
   
            // 获取按键码 keyCode 
            StringBuilder sb = new StringBuilder(); 
            // 这些都是可能的按键码 , 打印出来用户按下的键 
            if (KeyEvent.KEYCODE_MEDIA_NEXT == keyCode) { 
                sb.append("KEYCODE_MEDIA_NEXT"); 
            
            // 说明:当我们按下MEDIA_BUTTON中间按钮时,实际出发的是 KEYCODE_HEADSETHOOK 而不是 
            // KEYCODE_MEDIA_PLAY_PAUSE 
            if (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE == keyCode) { 
                sb.append("KEYCODE_MEDIA_PLAY_PAUSE"); 
            
            if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) { 
                sb.append("KEYCODE_HEADSETHOOK"); 
            
            if (KeyEvent.KEYCODE_MEDIA_PREVIOUS == keyCode) { 
                sb.append("KEYCODE_MEDIA_PREVIOUS"); 
            
            if (KeyEvent.KEYCODE_MEDIA_STOP == keyCode) { 
                sb.append("KEYCODE_MEDIA_STOP"); 
            
            // 输出点击的按键码 
            Log.i(TAG, sb.toString()); 
        
    
  
  2、  在AndroidManifest.xml声明我们定义的广播类。
  
[java] view plaincopyprint?
 <receiver android:name="MediaButtonReceiver"
  <intent-filter > 
        <action android:name="android.intent.action.MEDIA_BUTTON"></action> 
  </intent-filter> 
</receiver> 
  
         在模拟器上,我们可以手动构造MEDA_BUTTON的广播,并且将它发送出去(后面会介绍)。
         如果有真机测试的话,按下MEDIA_BUTTON是可以接受到MEDIA_BUTTON广播的,如果没有接受到,请关闭所有应用
   程序,在观察效果。
  
  继续我们的下一步分析:
         前面我们说明通过registerMediaButtonEventReceiver(eventReceiver)方法注册时,使它成为MEDIA_BUTTON的
     唯一 接收器。这个唯一是怎么实现的呢? 我们在源码中,一步步追本溯源,相信一定可以找到答案,知道这“唯一“是
    怎么来的。
  
第一步、   为AudioManager注册一个MediaButtonReceiver() ;
[java] view plaincopyprint?
//获得AudioManager对象 
AudioManager mAudioManager =(AudioManager)getSystemService(Context.AUDIO_SERVICE);    
//构造一个ComponentName,指向MediaoButtonReceiver类 
//下面为了叙述方便,我直接使用ComponentName类来替代MediaoButtonReceiver类 
ComponentName  mbCN = new ComponentName(getPackageName(),MediaButtonReceiver.class.getName()); 
//注册一个MedioButtonReceiver广播监听 
mAudioManager.registerMediaButtonEventReceiver(mbCN); 
//取消注册的方法 
mAudioManager.unregisterMediaButtonEventReceiver(mbCN); 
          
        MediaButtonReceiver就是我们用来接收MEDIA_BUTTON的广播类,下面为了叙述方便和直观上得体验,我直接使用
    ComponentName类来替代真正的MediaoButtonReceiver广播类。
  
   说明 接下来分析的文件路径全部在   frameworks/base/media/java/android/media/ 下
  
 第二步、 进入AudioManager.java进行查看 ,发现如下方法:
  
[java] view plaincopyprint?
//注册的方法为: 
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 
      //TODO enforce the rule about the receiver being declared in the manifest 
      //我们继续查看getService()方法,看看IAudioService类到底是什么? 
       IAudioService service = getService(); 
      try
        //只是简单的调用了service的方法来完成注册,继续跟踪 
          service.registerMediaButtonEventReceiver(eventReceiver); 
        
      } catch (RemoteException e) { 
          Log.e(TAG, "Dead object in registerMediaButtonEventReceiver"+e); 
      
//取消注册的方法为 
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 
      IAudioService service = getService();   
      try
        //只是简单的调用了service的方法来取消注册,,继续跟踪 
          service.unregisterMediaButtonEventReceiver(eventReceiver); 
      } catch (RemoteException e) { 
          Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiver"+e); 
      
  
 
  找到getService()方法,其实现为:
[java] view plaincopyprint?
  //看看它到底是什么 
  private static IAudioService getService() 
    
               // 单例模式,大家懂得 
        if (sService != null) { 
            return sService; 
       
       //了解Binder机制 以及AIDL文件的使用,就明白了这不过是通过AIDL文件定义的Java层Binder机制 
        //b为IBinder基类接口 
        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 
       //强制转换后,sService不过是一个客户端对象,IAudioService就是aidl文件定义的接口了 
        sService = IAudioService.Stub.asInterface(b); 
       return sService; 
    }     
//sService对象的声明 
         private static IAudioService sService; //单例模式,不足为奇了 
 
         我们知道了AudiaoManager只不过是一个傀儡,所有的方法都是由IAudioService 对象去实现的,通过它的构造方式,
  可以知道它应该是有AIDL文件形成的Binder机制, sService只是客户端对象,那么它的服务端对象在什么地方呢?
  也就是继承了IAudioService.Stub桩的类。
  
第三步、接下来我们需要找到该IAudioService.aidl文件和真正的服务端对象 
  
   IAudioService.aidl定义如下:
[java] view plaincopyprint?
package android.media; 
   
import android.content.ComponentName; 
import android.media.IAudioFocusDispatcher; 
/**
 * {@hide}
 */ 
interface IAudioService { 
       
    void adjustVolume(int direction, int flags); 
    void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags); 
    void adjustStreamVolume(int streamType, int direction, int flags);         
    void setStreamVolume(int streamType, int index, int flags);         
    void setStreamSolo(int streamType, boolean state, IBinder cb);           
    void setStreamMute(int streamType, boolean state, IBinder cb);       
    int getStreamVolume(int streamType);         
    int getStreamMaxVolume(int streamType);        
    void setRingerMode(int ringerMode);         
    int getRingerMode(); 
    void setVibrateSetting(int vibrateType, int vibrateSetting);         
    int getVibrateSetting(int vibrateType);         
    boolean shouldVibrate(int vibrateType); 
    void setMode(int mode, IBinder cb); 
    int getMode(); 
    oneway void playSoundEffect(int effectType);       
    oneway void playSoundEffectVolume(int effectType, float volume); 
    boolean loadSoundEffects();      
    oneway void unloadSoundEffects(); 
    oneway void reloadAudioSettings(); 
    void setSpeakerphoneOn(boolean on); 
    boolean isSpeakerphoneOn(); 
    void setBluetoothScoOn(boolean on); 
    boolean isBluetoothScoOn(); 
    int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l, String clientId); 
    int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);         
    void unregisterAudioFocusClient(String clientId); 
    void registerMediaButtonEventReceiver(in ComponentName eventReceiver);   //这个方法是我们需要弄懂的 
    void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);  //这个方法也是是我们需要弄懂的 
    void startBluetoothSco(IBinder cb); 
    void stopBluetoothSco(IBinder cb); 
     
       真正的服务端对象就是继承了 IAudioService.Stub 桩的类,AudioService就是该服务端对象,其实AudioManager的
  所有操作都是由AudioService来实现的,它才是真正的老大。
 
第五步、   AudioService.java
[java] view plaincopyprint?
//AudioService类  
public class AudioService extends IAudioService.Stub { 
    //..... 
    //仅仅列出我们需要的方法 
    //这儿才是真正的注册MediaButtonReceiver的方法 
    public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 
        Log.i(TAG, "  Remote Control   registerMediaButtonEventReceiver() for " + eventReceiver); 
   
        synchronized(mRCStack) { 
          //调用它去实现注册ComponentName 
            pushMediaButtonReceiver(eventReceiver); 
        
    
       
   //在查看pushMediaButtonReceiver()方法  先理解一下两个知识点,很重要的。 
    //RemoteControlStackEntry内部类不过是对ComponentName类的进一步封装(感觉没必要在加一层进行封装了)  
    private static class RemoteControlStackEntry { 
        public ComponentName mReceiverComponent;// 属性 
          //TODO implement registration expiration? 
        //public int mRegistrationTime; 
   
        public RemoteControlStackEntry() { 
        
   
        public RemoteControlStackEntry(ComponentName r) { 
            mReceiverComponent = r;// 构造函数赋值给mReceiverComponent对象 
        
    
       
   //采用了栈存储结构(先进后出)来保存所有RemoteControlStackEntry对象,也就是保存了ComponentName对象 
    private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 
      
   //回到pushMediaButtonReceiver()查看,这下该拨开云雾了吧,继续学习 
   private void pushMediaButtonReceiver(ComponentName newReceiver) { 
     // already at top of stack? 
        //采用了一个栈(前面我们介绍的知识点)来保存所有注册的ComponentName对象 
        //如果当前栈不为空并且栈顶的对象与新注册的ComponentName对象一样,不做任何事,直接返回 
        if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) { 
            return
        
        //获得mRCStack栈的迭代器 
        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 
        //循环 
        while(stackIterator.hasNext()) { 
          RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 
          //如果当前栈内保存该新注册的ComponentName对象,将它移除,跳出循环 
            if(rcse.mReceiverComponent.equals(newReceiver)) { 
                mRCStack.remove(rcse); 
                break
            
        
      //将新注册的ComponentName对象放入栈顶 
        mRCStack.push(new RemoteControlStackEntry(newReceiver)); 
    
  
小结一下:
 
         栈(mRCStack)维护了所有CompoentName对象,对每个CompoentName对象,保证它有且仅有一个,
     新注册的CompoentName对象永远处于栈顶   
 
  
 我们看下取消注册的方法:
[java] view plaincopyprint?
//我们看下取消注册的方法 
/** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */ 
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 
    Log.i(TAG, "  Remote Control   unregisterMediaButtonEventReceiver() for " + eventReceiver); 
   
    synchronized(mRCStack) { 
         //调用removeMediaButtonReceiver方法去实现 
        removeMediaButtonReceiver(eventReceiver); 
    
   
private void removeMediaButtonReceiver(ComponentName newReceiver) { 
    Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 
    while(stackIterator.hasNext()) { 
         //获得mRCStack栈的迭代器 
        RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 
        //如果存在该对象,则移除,跳出循环 
        if(rcse.mReceiverComponent.equals(newReceiver)) { 
            mRCStack.remove(rcse); 
            break
        
    
  
          通过对前面的学习,我们知道了AudioManager内部利用一个栈来管理包括加入和移除ComponentName对象,
    新的疑问来了?这个MEDIA_BUTTON广播是如何分发的呢 ?
  
         其实,AudioService.java文件中也存在这么一个MediaoButtonReceiver的广播类,它为系统广播接收器,即用来接收
  系统的MEDIA_BUTTON广播,当它接收到了这个MEDIA_BUTTON广播   ,它会对这个广播进行进一步处理,这个处理过程
   就是我们需要的弄清楚。
  
MediaButtonBroadcastReceiver 内部类如下:
  
[java] view plaincopyprint?
private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
        //获得action ,系统MEDIA_BUTTON广播来了 
        String action = intent.getAction(); 
        //action不正确 直接返回 
        if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) { 
            return
        
      //获得KeyEvent对象 
        KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 
        if (event != null) { 
            // if in a call or ringing, do not break the current phone app behavior 
            // TODO modify this to let the phone app specifically get the RC focus 
            //      add modify the phone app to take advantage of the new API 
            //来电或通话中,不做处理直接返回 
            if ((getMode() == AudioSystem.MODE_IN_CALL) ||(getMode() == AudioSystem.MODE_RINGTONE)) { 
                return
            
            synchronized(mRCStack) { 
                //栈不为空 
                if (!mRCStack.empty()) { 
                    // create a new intent specifically aimed at the current registered listener 
                    //构造一个Intent对象 ,并且赋予Action和KeyEvent 
                    Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 
                    targetedIntent.putExtras(intent.getExtras()); 
                    //指定该处理Intent的对象为栈顶ComponentName对象的广播类 
                        targetedIntent.setComponent(mRCStack.peek().mReceiverComponent); 
                    // trap the current broadcast 
                    // 终止系统广播 
                         abortBroadcast(); 
                    //Log.v(TAG, " Sending intent" + targetedIntent); 
                    //手动发送该广播至目标对象去处理,该广播不再是系统发送的了 
                        context.sendBroadcast(targetedIntent, null); 
                
                //假设栈为空,那么所有定义在AndroidManifest.xml的监听MEDIA_BUTTON的广播都会处理, 
                //在此过程中如果有任何应用程注册了registerMediaButton 该广播也会立即终止 
            
        
    
  
 总结一下MEDIA_BUTTON广播:
     
         AudioManager也就是AudioService服务端对象内部会利用一个栈来管理所有ComponentName对象,所有对象有且仅有一个,
   新注册的ComponentName总是会位于栈顶。
  
         当系统发送MEDIA_BUTTON,系统MediaButtonBroadcastReceiver 监听到系统广播,它会做如下处理:
                 1、 如果栈为空,则所有注册了该Action的广播都会接受到,因为它是由系统发送的。
                 2、 如果栈不为空,那么只有栈顶的那个广播能接受到MEDIA_BUTTON的广播,手动发送了MEDIA_BUTTON
                      广播,并且指定了目标对象(栈顶对象)去处理该MEDIA_BUTTON 。
 下面分析一下KeyEvent对象里的KeyCode按键,可能的按键码有:
 
       1、KeyEvent.KEYCODE_MEDIA_NEXT
       2、KeyEvent.KEYCODE_HEADSETHOOK
       3、KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE(已废除,等同于KEYCODE_HEADSETHOOK)
       4、KeyEvent.KEYCODE_MEDIA_PREVIOUS
       5、KeyEvent.KEYCODE_MEDIA_STOP
     
    PS : 在我的真机测试中,按下MEDIA_BUTTON只有KEYCODE_HEADSETHOOK可以打印出来了。
  
下面给出一个小DEMO检验一下我们之前所做的一切,看看MEDIA_BUTTON是如何处理分发广播的。
  
   编写两个MediaButtonReceiver类用来监听MEDIA_BUTTON广播:
  
  1 、China_MBReceiver.java
[java] view plaincopyprint?
package com.qin.mediabutton; 
   
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.util.Log; 
import android.view.KeyEvent; 
   
public class China_MBReceiver extends BroadcastReceiver  { 
   
    private static String TAG = "China_MBReceiver"
    @Override 
    public void onReceive(Context context, Intent intent) { 
        //获得Action  
        String intentAction = intent.getAction() ; 
        //获得KeyEvent对象 
        KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 
           
        Log.i(TAG, "Action ---->"+intentAction + "  KeyEvent----->"+keyEvent.toString()); 
           
        if(Intent.ACTION_MEDIA_BUTTON.equals(intentAction)){ 
            //获得按键字节码 
            int keyCode = keyEvent.getKeyCode() ; 
            //按下 / 松开 按钮 
            int keyAction = keyEvent.getAction() ; 
            //获得事件的时间 
            long downtime = keyEvent.getEventTime(); 
               
            //获取按键码 keyCode  
            StringBuilder sb = new StringBuilder(); 
            //这些都是可能的按键码 , 打印出来用户按下的键 
            if(KeyEvent.KEYCODE_MEDIA_NEXT == keyCode){ 
                sb.append("KEYCODE_MEDIA_NEXT"); 
            
            //说明:当我们按下MEDIA_BUTTON中间按钮时,实际出发的是 KEYCODE_HEADSETHOOK 而不是 KEYCODE_MEDIA_PLAY_PAUSE 
            if(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ==keyCode){ 
                sb.append("KEYCODE_MEDIA_PLAY_PAUSE"); 
            
            if(KeyEvent.KEYCODE_HEADSETHOOK == keyCode){ 
                sb.append("KEYCODE_HEADSETHOOK"); 
            
            if(KeyEvent.KEYCODE_MEDIA_PREVIOUS ==keyCode){ 
                sb.append("KEYCODE_MEDIA_PREVIOUS"); 
            
            if(KeyEvent.KEYCODE_MEDIA_STOP ==keyCode){ 
                sb.append("KEYCODE_MEDIA_STOP"); 
            
            //输出点击的按键码 
            Log.i(TAG, sb.toString()); 
               
        
           
    
   
  
   2 、England_MBReceiver.java同于China_MBRreceiver ,打印Log TAG= "England_MBReceiver"
   3、在AndroidManifest.xml文件定义:
[java] view plaincopyprint?
<strong>  <receiver android:name=".China_MBReceiver"
          <intent-filter > 
                <action android:name="android.intent.action.MEDIA_BUTTON"></action> 
          </intent-filter> 
        </receiver> 
           
         <receiver android:name=".Enaland_MBReceiver"
          <intent-filter > 
                <action android:name="android.intent.action.MEDIA_BUTTON"></action> 
          </intent-filter> 
        </receiver></strong> 
 
4、MainActivity .java 我们通过手动构造一个MEDIA_BUTTON广播去查看我们的MediaButtonReceiver类的打印信息。
  
[java] view plaincopyprint?
package com.qin.mediabutton; 
   
import android.app.Activity; 
import android.content.ComponentName; 
import android.content.Context; 
import android.content.Intent; 
import android.media.AudioManager; 
import android.os.Bundle; 
import android.view.KeyEvent; 
   
public class MainActivity extends Activity { 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
           
        //由于在模拟器上测试,我们手动发送一个MEDIA_BUTTON的广播,有真机更好处理了 
        Intent mbIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 
        //构造一个KeyEvent对象 
        KeyEvent keyEvent = new KeyEvent (KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_HEADSETHOOK) ; 
        //作为附加值添加至mbIntent对象中 
        mbIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 
   
        //此时China_MBReceiver和England_MBReceiver都会接收到该广播 
        sendBroadcast(mbIntent); 
           
           
        AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); 
        //AudioManager注册一个MediaButton对象 
        ComponentName chinaCN = new ComponentName(getPackageName(),China_MBReceiver.class.getName()); 
        //只有China_MBReceiver能够接收到了,它是出于栈顶的。 
        //不过,在模拟上检测不到这个效果,因为这个广播是我们发送的,流程不是我们在上面介绍的。 
        mAudioManager.registerMediaButtonEventReceiver(chinaCN); 
       //sendBroadcast(mbIntent,null); 
    
   //当一个Activity/Service死去时,我们需要取消这个MediaoButtonReceiver的注册,如下 
    protected void onDestroy(){ 
        super.onDestroy() ; 
        AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); 
        ComponentName chinaCN = new ComponentName(getPackageName(),China_MBReceiver.class.getName()); 
        //取消注册 
        mAudioManager.unregisterMediaButtonEventReceiver(chinaCN); 
    
  
       值得注意的一点时,当我们为一个应用程序注册了MediaoButtonReceiver时,在程序离开时,我们需要取消该
  MediaoButtonReceiver的注册,在onDestroy()调用unregisterMediaButtonEventReceiver()方法就OK,这样应用程序之间
  的交互就更具逻辑性了。

android 耳机按钮,布布扣,bubuko.com

android 耳机按钮

上一篇:Android开发学习之Xml解析归纳


下一篇:Application.Exit()结束程序,但线程还在的解决方法