Android6.0 call number and phone book contact to match _android

Source: Internet
Author: User
Tags null null

This article describes how the system can match contacts in a phone book after receiving incoming calls. The analysis starts with the code that is related to this article from another article (based on Android6.0 's RIL Framework Layer module analysis).

Packages/service/***/call.java public void Handlecreateconnectionsuccess (Callidmapper idmapper, ParcelableConnect

 Ion connection) {SetHandle (Connection.gethandle (), connection.gethandlepresentation ());//This function is important to start a query

 Setcallerdisplayname (Connection.getcallerdisplayname (), connection.getcallerdisplaynamepresentation ());

 Setextras (Connection.getextras ());  if (misincoming) {//We don't handle incoming calls immediately when they are by the verified/service. We allow the "Caller-info-query code to execute" We can read the//Direct-to-voicemail property before Dec

 IDing if we want to show the incoming call to//the user or if we want to reject the call.

 Mdirecttovoicemailquerypending = true; Timeout The Direct-to-voicemail lookup execution so, we dont wait too long before//showing the user the Incomin

 G Call screen. Mhandler.postdelayed (mdirecttovoicemailrunnable, Timeouts.getdirecttovoicemailmillis (mContext.getContEntresolver ()));
 }

}

This sethandle function is as follows:

Call.java public

void SetHandle (Uri handle, int presentation) {

 startcallerinfolookup ();

}

private void Startcallerinfolookup () {

 final String number = Mhandle = = null Null:mHandle.getSchemeSpecificPart ();

 mquerytoken++//Updated so previous queries can no longer set the information.

 Mcallerinfo = null;

 if (! Textutils.isempty (number) {

 mhandler.post (new Runnable () {

  @Override public

  void Run () {

  Mcallerinfoasyncqueryfactory.startquery (Mquerytoken,

   mcontext,number,mcallerinfoquerylistener,call.this);

  });

 }

}

Notice the runnable on the back post. This is the logic to start the query number. This mcallerinfoasyncqueryfactory's assignment process is more tortuous. The Initializetelecomsystem function is invoked when the Telecomservice is called Onbind on the connection. So where did this telecomservice get started? Inside the Telecomloaderservice.java defines:

 private static final componentname service_component = new ComponentName (" Com.androi

D.server.telecom "," Com.android.server.telecom.components.TelecomService "); private void connecttotelecom () {synchronized (mlock) {telecomserviceconnection serviceconnection = new Telecomservi

 Ceconnection ();

 Intent Intent = new Intent (service_action);

 Intent.setcomponent (service_component); Bind to Telecom and register the service if (Mcontext.bindserviceasuser intent, serviceconnection, flags, Userhandle.

 OWNER)) {mserviceconnection = serviceconnection; }} public void onbootphase (int phase) {//This triggers if (phase = = Phase_activity_manager_ready) {Connecttoteleco in the system boot phase

 M (); }}

So from here, the Telecomservice service is triggered during the boot phase of the system, and after a successful connection to the service, Servicemanager.addservice is invoked (Context.telecom_service, Service) to add the services to the system service. In the constructor of this class, an internal anonymous object is instantiated when the function Initializetelecomsystem initialization telecomsystem is invoked. The anonymous object is passed in when a mcallsmanager is initialized in the Telecomsystem constructor, and a call object is initialized with this function in Callsmanager's processincomingcallintent. So the actual content of this mcallerinfoasyncqueryfactory is seen in the Initializetelecomsystem in Telecomservice:

Telecomservice.java

telecomsystem.setinstance (

 new Telecomsystem

 , new

 Missedcallnotifierimpl (Context.getapplicationcontext ()),

 new Callerinfoasyncqueryfactory () {

  @Override Public

  callerinfoasyncquery startquery (int token, context,

   String number, Callerinfoasyncquery.onquerycompletelistener Listener,

   Object cookie) {

  return Callerinfoasyncquery.startquery (token, context, number, listener, cookie);

  },

 new Headsetmediabuttonfactory () {},

 new Proximitysensormanagerfactory () {},

 new Incallwakelockcontrollerfactory () {},

 new Vicenotifier () {}));

You can see the action of the Startquery to query for the incoming number. Let's look at the Startquery function of Callerinfoasyncquery.

Frameworks/base/telephony/java/com/android/internal/callerinfoasyncquery.java/** * Factory to start the Quer

 Y based on a number. * * Note:if The number contains a "@" character we treat it * as a SIP address, and look it up directly in the Data

 Table * Rather than using the Phonelookup table. 

 * Todo:but Eventually we should expose two separate, one for * methods and one for SIP numbers, and addresses then

 * Phoneutils.startgetcallerinfo () decide which one to call based on * The phone type of the incoming connection. */public static callerinfoasyncquery startquery (int token, context, String number, Onquerycompletelistener l

 Istener, Object cookie) {int subId = Subscriptionmanager.getdefaultsubid ();

 Return Startquery (token, context, number, listener, Cookie, subId);

 }/** * Factory to start the query with a Uri query spec.
*/public static callerinfoasyncquery startquery (int token, context, Uri contactref,
  Onquerycompletelistener Listener, Object cookie) {c.mhandler.startquery (token, CW,//Cookie contactref,// URI, note the query address here NULL,//projection null,//Selection null,//Selectionargs null);
by return C;
 }

Note that the function also handles the SIP number (which contains the @ number), as well as the emergency number and voice mail number to differentiate. In fact, when a number is queried, the three startquery are used. Note that the above startquery will modify the value of the connection according to the result.

The data is converted into a URI format, and subsequent queries are made on this data:

Frameworks/base/***/callerinfoasyncquery.java public static callerinfoasyncquery startquery (int token, context Context, String number, Onquerycompletelistener listener, object cookie, int subId) {//construct the URI Object and Que
 Ry params, and start the query. Final Uri contactref = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon (). Appendpath (number). Appendqueryparameter (Phonelookup.query_parameter_sip_address, string.valueof (Phonenumberutils.isurinumber (
 )). build ();
 Callerinfoasyncquery C = new Callerinfoasyncquery ();
 C.allocate (context, contactref);
 Create Cookiewrapper, start query Cookiewrapper CW = new Cookiewrapper (); Cw.listener = listener;
 Cw.cookie = cookie; Cw.number = number;
 Cw.subid = subId;
 Check to the If these are are recognized numbers, and use shortcuts if we can.
 if (Phonenumberutils.islocalemergencynumber (context, number)) {cw.event = Event_emergency_number; else if (Phonenumberutils.isvoicemailnumber (subId, number)) {Cw.event = Event_voicemail_number;
 else {cw.event = Event_new_query;
    } c.mhandler.startquery (token, CW,//Cookie contactref,//URI null,//projection null,//Selection NULL,//Selectionargs null);
by return C;
 }

The value of the contactref in this function should be "Content://com.android.contacts/phone_lookup_enterprise/13678909678/sip?" Like that.

In fact, this query is the Startquery function that calls Callerinfoasyncqueryhandler, and this function is the same as the parent class Asyncqueryhandler that calls it directly.

Asyncqueryhandler.java public
void startquery (int token, Object cookie, Uri Uri,
 string[] projection, String Selection, string[] Selectionargs,
 String by) {
 //Use the token as what so canceloperations works properly
   message msg = mworkerthreadhandler.obtainmessage (token);
 MSG.ARG1 = Event_arg_query;
 Workerargs args = new Workerargs ();
 Args.handler = this;
 Args.uri = URI;
 Msg.obj = args;
 Mworkerthreadhandler.sendmessage (msg);


This mworkerthreadhandler is assigned in the Createhandler function of the Callerinfoasyncqueryhandler function to overwrite the parent class, which is the Callerinfoworkerhandler type. So the subsequent handler function is the Handlemessage function of the class.

//asyncqueryhandler.java public void Handlemessage (msg) {Workerargs args = (Wo
 Rkerargs) Msg.obj;
 Cookiewrapper CW = (cookiewrapper) Args.cookie;
 if (CW = null) {//Normally, this should never is the case for calls originating//out within this code. However, if there is any code so this Handler calls (such as in//super.handlemessage) that does place unexpected m
 Essages on the//queue, then we need pass this messages on. else {switch (cw.event) {case event_new_query://its value is the same as Asyncqueryhandler Event_arg_query, is 1//start the SQL comma
  nd.
  Super.handlemessage (msg);
  Break
  Case Event_end_of_queue://query is already completed, so just send the reply.
  Passing the original token value back to the caller//on top of the event values in Arg1.
  Message reply = Args.handler.obtainMessage (msg.what);
  Reply.obj = args;
  REPLY.ARG1 = MSG.ARG1;
  Reply.sendtotarget ();
  Break Default:}}} 

This super is the inner class workerhandler of Asyncqueryhandler.

//asyncqueryhandler.java protected class Workerhandler extends Handler {@Override Pub
 LIC void Handlemessage (Message msg) {final Contentresolver resolver = Mresolver.get ();
 Workerargs args = (Workerargs) msg.obj;
 int token = Msg.what;
 int event = MSG.ARG1;
  Switch (event) {case Event_arg_query:cursor Cursor;
   try {cursor = Resolver.query (Args.uri, Args.projection, Args.selection, Args.selectionargs, Args.orderby); Calling GetCount () causes the cursor window to be filled,//which'll make the the the main thread A
   Lot faster.
   if (cursor!= null) {Cursor.getcount ();
  } args.result = cursor;
 Break
 }//Passing the original token value back to the caller//on top of the event values in Arg1.

 Message reply = Args.handler.obtainMessage (token);
 Reply.obj = args;
 REPLY.ARG1 = MSG.ARG1;
 Reply.sendtotarget (); }}

You can see that the process is simply using Resolver.query to query the specified query URI, and then sending the return value through the message mechanism to Asyncqueryhandler's handlemessage. And here you call the Callerinfoasyncquery onquerycomplete function. Note that this contentresolver is the result of the query on the URI, which is provided by a contentprovider. Notice that the value in the authorities inside the address is "com.android.contacts," and also look at the Contactsprovider androidmanifest.xml file:

<provider android:name= "ContactsProvider2"
  android:authorities= "Contacts;com.android.contacts"
  android:readpermission= "Android.permission.READ_CONTACTS"
  android:writepermission= " Android.permission.WRITE_CONTACTS ">
  <path-permission android:pathprefix="/search_suggest_query "
   android:readpermission= "Android.permission.GLOBAL_SEARCH"/>
  <path-permission android:pathpattern= " Contacts/.*/photo "   android:readpermission=" Android.permission.GLOBAL_SEARCH "/>
  < Grant-uri-permission android:pathpattern= ". *"/>
 </provider>

So the last query was executed by Contactsprovider.

Let's take a look at the specific process of calling the Callerinfoasyncquery onquerycomplete function after the query is complete:

protected void Onquerycomplete (int token, Object cookie, Cursor Cursor) {
 //Check the token and if needed, create the Callerinfo object.
 if (Mcallerinfo = = null) {
  if (cw.event = = Event_emergency_number) {
  } else if (cw.event = = Event_voicemail_number {
  } else {
  mcallerinfo = Callerinfo.getcallerinfo (Mcontext, Mqueryuri, cursor);
 }}} Notify the listener that's the query is complete.
 if (Cw.listener!= null) {
  cw.listener.onQueryComplete (token, Cw.cookie, mcallerinfo);}}}


Note that the callerinfo.getcallerinfo in the above code is very important. In this case, the cursor result of the query processing is used, and the appropriate results are populated to the mcallerinfo and passed to the Cw.listener.onQueryComplete function for further processing as the final result.

Callerinfo.java public
Static Callerinfo getcallerinfo (context, Uri contactref, Cursor Cursor) {
 Callerinfo info = new Callerinfo ();
 if (cursor!= null) {
 if (Cursor.movetofirst ()) {
  columnindex = Cursor.getcolumnindex (Phonelookup.lookup_key);
  if (columnindex!=-1) {
  Info.lookupkey = cursor.getstring (columnindex);

  }
  Info.contactexists = true;
 }
 Cursor.close ();
 cursor = null;
 }
 Info.needupdate = false;
 Info.name = normalize (info.name);
 Info.contactrefuri = Contactref;
 return info;
}

The system native logic is the first record of the search results, and is used for instantiation. When the customer needs to change, need to match different numbers, you need to modify this place. The first priority is to traverse the entire cursor set and select the appropriate result based on the customer's needs, assigning value to the Callerinfo instance.

Here is a flowchart of the entire number matching:


Call.java will set the result of the query to the call instance and transfer it to the Callsmanager for subsequent processing. And this callsmanager will show the call to the customer.

When the network end calls, the frame layer receives, and the connection succeeds and triggers the handlecreateconnectionsuccess inside the Call.java. This function logic is to query the contact person for the composite requirement from the database, and only the first record of the result set is used to initialize the variable in this call. The call is then uploaded to Callsmanager for processing and displayed to the user.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.