Android about the media control process to solve Mediabutton learning

Source: Internet
Author: User

Problem background: The phone connected to the headset, in the process of the short press button is hung up the phone, long press the button is the call mute. Customer demand is to change the long press to hang up function, short press is mute function.

Android Version: 8.1

In the call, test print information, you can see the button keycode is 79, corresponding to the key Keycode_headsethook.

Phonewindowmanager-->interceptkeybeforequeueing ()-->case Keycode_headsethook

=new  keyevent (event)); Msg.setasynchronous (true); Msg.sendtotarget ();

Send the message out here and handle the Msg_dispatch_media_key_with_wake_lock in Handlemessage

 Case Msg_dispatch_media_key_with_wake_lock:    dispatchmediakeywithwakelock ((keyevent) msg.obj);     break;

In the Dispatchmediakeywithwakelock () method,

void Dispatchmediakeywithwakelock (KeyEvent event) {    ...    Dispatchmediakeywithwakelocktoaudioservice (event);    ...}

The event is then passed on to the Dispatchmediakeywithwakelocktoaudioservice (event).

It then calls the

true);

The continuation of the event gave Mediasession,mediasessionlegacyhelper.gethelper (Mcontext) a Mediasessionlegacyhelper object, Then look at Mediasessionlegacyhelper's sendmediabuttonevent ()

 Public void Boolean Needwakelock) {    ifnull) {        "tried to send a null key event. Ignoring. " );         return ;    }    Msessionmanager.dispatchmediakeyevent (KeyEvent, needwakelock);     if (DEBUG) {        "dispatched media key" + KeyEvent);}    }

and passed the event on to Msessionmanager, Dispatchmediakeyevent.

 Public void Boolean Needwakelock) {    try  {        mservice.dispatchmediakeyevent (keyevent, needwakelock);     Catch (RemoteException e) {        "Failed to send key event." , E);}    }

The object of this mservice is Isessionmanager, found that this is the application of Aidl process communication, Isessionmanager is just an interface, its implementation classes are class Sessionmanagerimpl extends isessionmanager.stub{}, This sessionmanagerimpl is Mediasessionservice.java's inner class, and Mediasessionservice is a system service that controls a lot of media-related functions.

Then look at Sessionmanagerimpl's dispatchmediakeyevent ()

@Override  Public void Boolean Needwakelock) {    ...      if (!isglobalpriorityactive && Isvoicekey (Keyevent.getkeycode ())) {        "dispatchmediakeyevent: Handlevoicekeyeventlocked ");        Handlevoicekeyeventlocked (KeyEvent, needwakelock);      Else {        "dispatchmediakeyeventlocked");        Dispatchmediakeyeventlocked (KeyEvent, Needwakelock);     }    ... }

Omit some code in the middle, in passing the event, made a judgment to pass the way is Voicekey, our headset is only a button, so then go dispatchmediakeyeventlocked ()

 private  void  Dispatchmediakeyeventlocked (KeyEvent keyevent, boolean   Needwakelock) {Mediasessionrecord session  =    Mcurrentfulluserrecord.getmediabuttonsessionlocked ();  if  (Session! = null  ) {....   //  If we don ' t need a wakelock use-1 as the ID so We won ' t release it later.  session.sendmediabutton (keyevent, Needwakelock ? mkeyeventreceiver.mlas Ttimeoutid: -1, Mkeyeventreceiver, Process.system_uid, Getcont        Ext (). Getpackagename ());    。。。。 }}

This will pass keyevent a session, what is this session? I don't know, it should be something like a token, a class that records the current media information Mediasessionrecord.java

Look into the Mediasessionrecord.java, which has many setup methods to find Sendmediabutton

 Public void int SequenceID,         int uid, String packagename) {    updatecallingpackage (uid, packagename);    Msessioncb.sendmediabutton (Ke, SequenceID, CB);}

Here the MSESSIONCB is also a special class, in this section, you will find there are many traces of inter-process communication, various aidl output.

classSESSIONCB {Private FinalIsessioncallback mCb;  PublicSESSIONCB (Isessioncallback cb) {mCb=CB; }     Public BooleanSendmediabutton (KeyEvent keyevent,intSequenceID, Resultreceiver CB) {Intent mediabuttonintent=NewIntent (Intent.action_media_button);        Mediabuttonintent.putextra (Intent.extra_key_event, keyevent); Try{Mcb.onmediabutton (mediabuttonintent, SequenceID, CB); return true; } Catch(RemoteException e) {slog.e (TAG,"Remote failure in Sendmediarequest.", E); }        return false; }

Here, Sendmediabutton and then keyevent into a intent, passed to the Mcb.onmediabutton

This MCB is a aidl implementation, Isessioncallback is an interface that needs to find the real class that inherits it, the global search finds

public static class Callbackstub extends Isessioncallback.stub implements this interface, Here in Mediasession.java's inner class, look at the path, you will find Mediasessionrecord.java in the framwork/service/subdirectory, and Mediasession.java in framwork/ base/media/Sub-directory, cross-process communication is obviously necessary to use the aidl.

In the Onmediabutton.

@Override  Public void int SequenceNumber,        Resultreceiver CB) {    = mmediasession.get ();     Try {        ifnull) {            Session.dispatchmediabutton (mediabuttonintent);        }    }}

will continue to walk Dispatchmediabutton

Private void Dispatchmediabutton (Intent mediabuttonintent) {    posttocallback (Callbackmessagehandler.msg_media_button, mediabuttonintent);}

Posttocallback the intent to Callbackmessagehandler.

In this handler, MSG and intent are processed.

Handlemessage.

 Case Msg_media_button:    mcallback.onmediabuttonevent ((Intent) msg.obj);     break;

This mcallback callback, which came when the Callbackmessagehandler was created,

 Public Callbackmessagehandler (Looper Looper, Mediasession.callback Callback) {    supernull true );     = callback;      This ;}

Here, you need to find out who called the construction method to find the place to call Onmediabuttonevent from the callback.

After a global search, the Setcallback in Mediasession.java is called:

 Public void setcallback (@Nullable Callback Callback, @Nullable Handler Handler) {    ...         if NULL             {new  Handler ();        }          This ;         New Callbackmessagehandler (Handler.getlooper (),                callback);         = Msghandler,    ..... }

We need to find someone who called Mediasession's Setcallback method, global search, It is found that as long as there is a call to this method in Headsetmediabutton.java, and here belongs to a handler called Mmediasessionhandler,

 Case msg_media_session_initialize: {    new  mediasession (            mcontext,            Headsetmediabutton . class . Getsimplename ());    Session.setcallback (msessioncallback);    Session.setflags (mediasession.flag_exclusive_global_priority            |  mediasession.flag_handles_media_buttons);    Session.setplaybacktolocal (audio_attributes);     = session;      Break ;}

That's it, Headsetmediabutton.class.

In its construction method, there is an action to send a message, created from the beginning of the existence to produce a mediasession

 Public Headsetmediabutton (        context context,        Callsmanager Callsmanager,        telecomsystem.syncroot Lock) {     = context;     = Callsmanager;     = lock;     // Create a mediasession but don ' t enable it yet. This was a    //  replacement for Mediabuttonreceiver  Mmediasessionhandler.obtainmessage (msg_media_session_initialize). Sendtotarget ();}

The Msessioncallback is set in the Setcallback and continues to see what it is.

Private FinalMediasession.callback Msessioncallback =NewMediasession.callback () {@Override Public Booleanonmediabuttonevent (Intent Intent) {KeyEvent event=(keyevent) Intent.getparcelableextra (intent.extra_key_event); LOG.V ( This, "Sessioncallback.onmediabutton () ... event =%s.", event); if(Event! =NULL) && ((event.getkeycode () = = Keyevent.keycode_headsethook) | |(Event.getkeycode ()==Keyevent.keycode_media_play_pause)))  {            synchronized(MLock) {LOG.V ( This, "Sessioncallback:headsethook/media_play_pause"); Booleanconsumed =Handlecallmediabutton (event); LOG.V ( This, "==> Handlecallmediabutton (): consumed =%b.", consumed); returnconsumed; }        }        return true; }};

This callback, there's a method we're familiar with, onmediabuttonevent,

In mediasession processing Msg_media_button This case, is called the Mcallback onmediabuttonevent, and this callback implementation object is here Msessioncallback, Here Onmediabuttonevent intent to deal with, go to Handlecallmediabutton.

Private BooleanHandlecallmediabutton (KeyEvent event) {if(Event.islongpress ()) {returnMcallsmanager.onmediabutton (long_press); } Else if(event.getaction () = =keyevent.action_up) {        //We should not judge short_press by Action_up event RepeatCount, because it always//return 0. //actually Action_down event RepeatCount only increases when Long_press performed.if(Mlasthookevent! =NULL&& Mlasthookevent.getrepeatcount () = = 0) {            returnMcallsmanager.onmediabutton (short_press); }    }    return true;}

Here came the CallManager, yes, this is the place to manage call control, in CallManager

BooleanOnmediabutton (inttype) {    if(Hasanycalls ()) {call Ringingcall=getfirstcallwithstate (callstate.ringing); if(Headsetmediabutton.short_press = =type) {            if(Ringingcall = =NULL) {call Calltohangup=getfirstcallwithstate (callstate.ringing, callstate.dialing, callstate.pulling, Callstate.activ                E, Callstate.on_hold); Log.addevent (Calltohangup, LogUtils.Events.INFO,"Media btn Short press-end call."); if(Calltohangup! =NULL) {calltohangup.disconnect (); return true; }            } Else{ringingcall.answer (videoprofile.state_audio_only); return true; }        } Else if(Headsetmediabutton.long_press = =type) {            if(Ringingcall! =NULL) {log.addevent (Getforegroundcall (), LogUtils.Events.INFO,"Media btn Long Press-reject"); Ringingcall.reject (false,NULL); } Else{log.addevent (Getforegroundcall (), LogUtils.Events.INFO,"Media btn Long Press-mute");            Mcallaudiomanager.togglemute (); }            return true; }    }    return false;}

Is the place we're looking for, short press, and long press handling, here, short_press is answer and hang up, long_press is reject and mute control.

Therefore, we only need to change the control under the corresponding if condition, can complete the short-press and long-press customer customization function.

Summary: The whole process, from the key monitoring, to go to CallManager, spare a long time, in the middle encountered a lot of mediasession and interprocess communication knowledge, here just record the process of solving the bug, feel like guessing game, this is a process of technological growth. It's very meaningful.

Android about the media control process to solve Mediabutton learning

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.