1 /*
2  * Copyright (c) 2015, Motorola Mobility LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     - Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     - Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     - Neither the name of Motorola Mobility nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26  * DAMAGE.
27  */
28 
29 package com.android.service.ims.presence;
30 
31 import java.util.ArrayList;
32 import java.util.Calendar;
33 
34 import android.app.Service;
35 import android.app.AlarmManager;
36 import android.content.BroadcastReceiver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.database.ContentObserver;
41 import android.database.Cursor;
42 import android.net.Uri;
43 import android.os.Handler;
44 import android.os.HandlerThread;
45 import android.os.IBinder;
46 import android.os.Looper;
47 import android.os.Message;
48 import android.provider.ContactsContract;
49 import android.provider.ContactsContract.CommonDataKinds.Phone;
50 import android.text.TextUtils;
51 
52 import com.android.ims.internal.EABContract;
53 
54 import com.android.ims.RcsManager;
55 import com.android.ims.RcsPresence;
56 import com.android.ims.RcsException;
57 import com.android.ims.internal.Logger;
58 
59 public class EABService extends Service {
60 
61     private Logger logger = Logger.getLogger(this.getClass().getName());
62 
63     private Context mContext;
64     private Looper mServiceLooper = null;
65     private ServiceHandler mServiceHandler = null;
66     // Used to avoid any content observer processing during EABService
67     // initialisation as anyways it will check for Contact db changes as part of boot-up.
68     private boolean isEABServiceInitializing = true;
69 
70     private static final int BOOT_COMPLETED = 0;
71     private static final int CONTACT_TABLE_MODIFIED = 1;
72     private static final int CONTACT_PROFILE_TABLE_MODIFIED = 2;
73     private static final int EAB_DATABASE_RESET = 3;
74 
75     private static final int SYNC_COMPLETE_DELAY_TIMER = 3 * 1000; // 3 seconds.
76     private static final String TAG = "EABService";
77 
78     // Framework interface files.
79     private RcsManager mRcsManager = null;
80     private RcsPresence mRcsPresence = null;
81 
EABService()82     public EABService() {
83         super();
84         logger.info("EAB Service constructed");
85     }
86 
87     @Override
onBind(Intent arg0)88     public IBinder onBind(Intent arg0) {
89         return null;
90     }
91 
92     /**
93      * When "clear data" is done for contact storage in system settings, EAB
94      * Provider must be cleared.
95      */
96     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
97         @Override
98         public void onReceive(Context context, Intent intent) {
99             String action = intent.getAction();
100             logger.debug("onReceive intent: " + action);
101 
102             switch(action) {
103                 case ContactsContract.Intents.CONTACTS_DATABASE_CREATED: {
104                     logger.debug("Contacts database created.");
105                     // Delete all entries from EAB Provider as it has to be re-synced with
106                     // Contact db.
107                     mContext.getContentResolver().delete(
108                             EABContract.EABColumns.CONTENT_URI, null, null);
109                     // Initialise EABProvider.
110                     logger.debug("Resetting timestamp values in shared pref.");
111                     SharedPrefUtil.resetEABSharedPref(mContext);
112                     // init the EAB db after re-setting.
113                     ensureInitDone();
114                     break;
115                 }
116                 case Intent.ACTION_TIME_CHANGED:
117                     // fall through
118                 case Intent.ACTION_TIMEZONE_CHANGED: {
119                     Calendar cal = Calendar.getInstance();
120                     long currentTimestamp = cal.getTimeInMillis();
121                     long lastChangedTimestamp = SharedPrefUtil.getLastContactChangedTimestamp(
122                             mContext, currentTimestamp);
123                     logger.debug("lastChangedTimestamp=" + lastChangedTimestamp +
124                             " currentTimestamp=" + currentTimestamp);
125                     // Changed time backwards.
126                     if(lastChangedTimestamp > currentTimestamp) {
127                         logger.debug("Resetting timestamp values in shared pref.");
128                         SharedPrefUtil.resetEABSharedPref(mContext);
129                         // Set Init done to true as only the contact sync timestamps are cleared and
130                         // the EABProvider table data is not cleared.
131                         SharedPrefUtil.setInitDone(mContext, true);
132                         CapabilityPolling capabilityPolling = CapabilityPolling.getInstance(null);
133                         if (capabilityPolling != null) {
134                             capabilityPolling.enqueueDiscovery(
135                                     CapabilityPolling.ACTION_POLLING_NORMAL);
136                         }
137                     }
138                     break;
139                 }
140                 case Contacts.ACTION_EAB_DATABASE_RESET: {
141                     logger.info("EAB Database Reset, Recreating...");
142                     sendEABResetMessage();
143                     break;
144                 }
145             }
146         }
147     };
148 
149     private  ContentObserver mContactChangedListener = null;
150     private class ContactChangedListener extends ContentObserver {
ContactChangedListener()151         public ContactChangedListener() {
152             super(null);
153         }
154 
155         @Override
deliverSelfNotifications()156         public boolean deliverSelfNotifications() {
157             return false;
158         }
159 
160         @Override
onChange(boolean selfChange)161         public void onChange(boolean selfChange) {
162             logger.debug("onChange for ContactChangedListener");
163             sendDelayedContactChangeMsg();
164         }
165     }
166 
167     private  ContentObserver mContactProfileListener = null;
168     private class ContactProfileListener extends ContentObserver {
ContactProfileListener()169         public ContactProfileListener() {
170             super(null);
171         }
172 
173         @Override
deliverSelfNotifications()174         public boolean deliverSelfNotifications() {
175             return false;
176         }
177 
178         @Override
onChange(boolean selfChange)179         public void onChange(boolean selfChange) {
180             logger.debug("onChange for ContactProfileListener");
181             sendDelayedContactProfileMsg();
182         }
183     }
184 
185     @Override
onCreate()186     public void onCreate() {
187         logger.debug("Enter : onCreate");
188         mContext = getApplicationContext();
189         HandlerThread thread = new HandlerThread("EABServiceHandler");
190         thread.start();
191 
192         mServiceLooper = thread.getLooper();
193         if (mServiceLooper != null) {
194             mServiceHandler = new ServiceHandler(mServiceLooper);
195         } else {
196             logger.debug("mServiceHandler could not be initialized since looper is null");
197         }
198 
199         IntentFilter filter = new IntentFilter();
200         filter.addAction(ContactsContract.Intents.CONTACTS_DATABASE_CREATED);
201         filter.addAction(Intent.ACTION_TIME_CHANGED);
202         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
203         filter.addAction(Contacts.ACTION_EAB_DATABASE_RESET);
204         registerReceiver(mReceiver, filter);
205 
206         initializeRcsInterfacer();
207 
208         startResetContentObserverAlarm();
209         super.onCreate();
210     }
211 
212     @Override
onDestroy()213     public void onDestroy() {
214         cancelResetContentObserverAlarm();
215         unregisterContentObservers();
216         if (null != mReceiver) {
217             unregisterReceiver(mReceiver);
218         }
219         if (null != mServiceHandler) {
220             mServiceHandler = null;
221         }
222     }
223 
initializeRcsInterfacer()224     private void initializeRcsInterfacer() {
225         // Get instance of mRcsManagr.
226         if (null == mRcsManager) {
227             mRcsManager = RcsManager.getInstance(this, 0);
228         }
229         try{
230             if (null == mRcsPresence) {
231                 mRcsPresence = mRcsManager.getRcsPresenceInterface();
232                 logger.debug("mRcsManager : " + mRcsManager + " mRcsPresence : " + mRcsPresence);
233             }
234          }catch (RcsException e){
235              logger.error("getRcsPresenceInterface() exception : ", e);
236             mRcsPresence = null;
237          } catch (Exception e) {
238              logger.error("getRcsPresenceInterface() exception : ", e);
239             mRcsPresence = null;
240             mRcsManager = null;
241          }
242      }
243 
registerContentObservers()244     private void registerContentObservers() {
245         logger.debug("Registering for Contact and Profile Change Listener.");
246         mContactChangedListener = new ContactChangedListener();
247         getContentResolver().registerContentObserver(
248                 ContactsContract.Contacts.CONTENT_URI, true,
249                 mContactChangedListener);
250 
251         mContactProfileListener = new ContactProfileListener();
252         getContentResolver().registerContentObserver(
253                 ContactsContract.Profile.CONTENT_URI, true,
254                 mContactProfileListener);
255     }
256 
unregisterContentObservers()257     private void unregisterContentObservers() {
258         logger.debug("Un-registering for Contact and Profile Change Listener.");
259         if (null != mContactChangedListener) {
260             getContentResolver().unregisterContentObserver(
261                     mContactChangedListener);
262             mContactChangedListener = null;
263         }
264         if (null != mContactProfileListener) {
265             getContentResolver().unregisterContentObserver(
266                     mContactProfileListener);
267             mContactProfileListener = null;
268         }
269     }
270 
resetContentObservers()271     private void resetContentObservers() {
272         unregisterContentObservers();
273         registerContentObservers();
274     }
275 
276     private AlarmManager.OnAlarmListener mResetContentObserverListener = () -> {
277         logger.debug("mResetContentObserverListener Callback Received");
278 
279         resetContentObservers();
280         startResetContentObserverAlarm();
281     };
282 
startResetContentObserverAlarm()283     private void startResetContentObserverAlarm() {
284         logger.debug("startResetContentObserverAlarm: content Observers reset every 12 hours");
285         long startInterval = System.currentTimeMillis() + AlarmManager.INTERVAL_HALF_DAY;
286 
287         // Start the resetContentObservers Alarm on the ServiceHandler
288         ((AlarmManager) getSystemService(Context.ALARM_SERVICE)).set(AlarmManager.RTC_WAKEUP,
289                 startInterval, TAG, mResetContentObserverListener, mServiceHandler);
290     }
291 
cancelResetContentObserverAlarm()292     private void cancelResetContentObserverAlarm() {
293         ((AlarmManager) getSystemService(Context.ALARM_SERVICE)).cancel(
294                 mResetContentObserverListener);
295     }
296 
297     @Override
onStartCommand(Intent intent, int flags, int startId)298     public int onStartCommand(Intent intent, int flags, int startId) {
299         // As the return type is START_STICKY, check for null intent is not
300         // needed as if this service's process is killed while it is started,
301         // system will try to re-create the service with a null intent object if
302         // there are not any pending start commands
303         if (intent != null) {
304             logger.debug("Enter : onStartCommand for intent : " + intent.getAction());
305         }
306         registerContentObservers();
307         Message msg = mServiceHandler.obtainMessage(BOOT_COMPLETED);
308         mServiceHandler.sendMessage(msg);
309         // This service should be a always-on service.
310         return START_STICKY;
311     }
312 
313     private final class ServiceHandler extends Handler {
ServiceHandler(Looper looper)314         public ServiceHandler(Looper looper) {
315             super(looper);
316         }
317 
318         @Override
handleMessage(Message msg)319         public void handleMessage(Message msg) {
320             logger.debug("Enter: handleMessage");
321 
322             switch (msg.what) {
323             case BOOT_COMPLETED:
324                 logger.debug("case BOOT_COMPLETED");
325                 ensureInitDone();
326                 isEABServiceInitializing = false;
327                 break;
328             case CONTACT_TABLE_MODIFIED:
329                 logger.debug("case CONTACT_TABLE_MODIFIED");
330                 validateAndSyncFromContactsDb();
331                 break;
332             case CONTACT_PROFILE_TABLE_MODIFIED:
333                 logger.debug("case CONTACT_PROFILE_TABLE_MODIFIED");
334                 validateAndSyncFromProfileDb();
335                 break;
336             case EAB_DATABASE_RESET:
337                 // Initialise EABProvider.
338                 logger.debug("Resetting timestamp values in shared pref.");
339                 SharedPrefUtil.resetEABSharedPref(mContext);
340                 // init the EAB db after re-setting.
341                 ensureInitDone();
342                 break;
343             default:
344                 logger.debug("default usecase hit! Do nothing");
345                 break;
346             }
347             logger.debug("Exit: handleMessage");
348         }
349     }
350 
351     // synchronized is used to prevent sync happening in parallel due to
352     // multiple content change notifys from contacts observer.
validateAndSyncFromContactsDb()353     private synchronized void validateAndSyncFromContactsDb() {
354         logger.debug("Enter : validateAndSyncFromContactsDb()");
355         checkForContactNumberChanges();
356         checkForDeletedContact();
357         logger.debug("Exit : validateAndSyncFromContactsDb()");
358     }
359 
360     // synchronized is used to prevent sync happening in parallel due to
361     // multiple content change notify from contacts observer.
validateAndSyncFromProfileDb()362     private synchronized void validateAndSyncFromProfileDb() {
363         logger.debug("Enter : validateAndSyncFromProfileDb()");
364         checkForProfileNumberChanges();
365         checkForDeletedProfileContacts();
366         logger.debug("Exit : validateAndSyncFromProfileDb()");
367     }
368 
ensureInitDone()369     private void ensureInitDone() {
370         logger.debug("Enter : ensureInitDone()");
371         if(SharedPrefUtil.isInitDone(mContext)) {
372             logger.debug("EAB initialized already!!! Just Sync with Contacts db.");
373             validateAndSyncFromContactsDb();
374             validateAndSyncFromProfileDb();
375             return;
376         } else {
377             logger.debug("Initializing EAB Provider.");
378             // This API will sync the numbers from Contacts db to EAB db based on
379             // contact last updated timestamp.
380             EABDbUtil.validateAndSyncFromContactsDb(mContext);
381             // This API's will sync the profile numbers from Contacts db to EAB db based on
382             // contact last updated timestamp.
383             validateAndSyncFromProfileDb();
384             SharedPrefUtil.setInitDone(mContext, true);
385         }
386     }
387 
sendEABResetMessage()388     private void sendEABResetMessage() {
389         logger.debug("Enter: sendEABResetMsg()");
390         if (null != mServiceHandler) {
391             if (mServiceHandler.hasMessages(EAB_DATABASE_RESET)) {
392                 mServiceHandler.removeMessages(EAB_DATABASE_RESET);
393                 logger.debug("Removed previous EAB_DATABASE_RESET msg.");
394             }
395 
396             logger.debug("Sending new EAB_DATABASE_RESET msg.");
397             Message msg = mServiceHandler.obtainMessage(EAB_DATABASE_RESET);
398             mServiceHandler.sendMessage(msg);
399         }
400     }
401 
sendDelayedContactChangeMsg()402     private void sendDelayedContactChangeMsg() {
403         logger.debug("Enter: sendDelayedContactChangeMsg()");
404         if (null != mServiceHandler && !isEABServiceInitializing) {
405             // Remove any previous message for CONTACT_TABLE_MODIFIED.
406             if (mServiceHandler.hasMessages(CONTACT_TABLE_MODIFIED)) {
407                 mServiceHandler.removeMessages(CONTACT_TABLE_MODIFIED);
408                 logger.debug("Removed previous CONTACT_TABLE_MODIFIED msg.");
409             }
410 
411             logger.debug("Sending new CONTACT_TABLE_MODIFIED msg.");
412             // Send a new delayed message for CONTACT_TABLE_MODIFIED.
413             Message msg = mServiceHandler.obtainMessage(CONTACT_TABLE_MODIFIED);
414             mServiceHandler.sendMessageDelayed(msg, SYNC_COMPLETE_DELAY_TIMER);
415         }
416     }
417 
sendDelayedContactProfileMsg()418     private void sendDelayedContactProfileMsg() {
419         logger.debug("Enter: sendDelayedContactProfileMsg()");
420         if (null != mServiceHandler && !isEABServiceInitializing) {
421             // Remove any previous message for CONTACT_PROFILE_TABLE_MODIFIED.
422             if (mServiceHandler.hasMessages(CONTACT_PROFILE_TABLE_MODIFIED)) {
423                 mServiceHandler.removeMessages(CONTACT_PROFILE_TABLE_MODIFIED);
424                 logger.debug("Removed previous CONTACT_PROFILE_TABLE_MODIFIED msg.");
425             }
426 
427             logger.debug("Sending new CONTACT_PROFILE_TABLE_MODIFIED msg.");
428             // Send a new delayed message for CONTACT_PROFILE_TABLE_MODIFIED.
429             Message msg = mServiceHandler.obtainMessage(CONTACT_PROFILE_TABLE_MODIFIED);
430             mServiceHandler.sendMessageDelayed(msg, SYNC_COMPLETE_DELAY_TIMER);
431         }
432     }
433 
checkForContactNumberChanges()434     private void checkForContactNumberChanges() {
435         logger.debug("Enter: checkForContactNumberChanges()");
436         String[] projection = new String[] {
437                 ContactsContract.Data._ID,
438                 ContactsContract.Data.CONTACT_ID,
439                 ContactsContract.Data.RAW_CONTACT_ID,
440                 ContactsContract.Data.MIMETYPE,
441                 ContactsContract.Data.DATA1,
442                 ContactsContract.Data.DISPLAY_NAME,
443                 ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP };
444 
445         long contactLastChange = SharedPrefUtil.getLastContactChangedTimestamp(mContext, 0);
446         logger.debug("contactLastChange : " + contactLastChange);
447 
448         String selection = ContactsContract.Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE +
449                 "' AND " + ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP  + " > '" +
450                 contactLastChange + "'";
451         String sortOrder = ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP + " desc";
452         Cursor cursor = null;
453         try {
454             cursor = getContentResolver().query(ContactsContract.Data.CONTENT_URI,
455                     projection, selection, null, sortOrder);
456 
457             if (null != cursor) {
458                 int count = cursor.getCount();
459                 logger.debug("cursor count : " + count);
460                 if (count > 0) {
461                     ArrayList<Long> uniqueRawContactIds = new ArrayList<Long>();
462                     while (cursor.moveToNext()) {
463                         Long dataId = Long.valueOf(cursor.getLong(cursor.getColumnIndex(
464                                 ContactsContract.Data._ID)));
465                         Long contactId = Long.valueOf(cursor.getLong(cursor.getColumnIndex(
466                                 ContactsContract.Data.CONTACT_ID)));
467                         Long rawContactId = Long.valueOf(cursor.getLong(cursor.getColumnIndex(
468                                 ContactsContract.Data.RAW_CONTACT_ID)));
469                         String phoneNumber = cursor.getString(cursor.getColumnIndex(
470                                 ContactsContract.Data.DATA1));
471                         String displayName = cursor.getString(cursor.getColumnIndex(
472                                ContactsContract.Data.DISPLAY_NAME));
473                         logger.debug("dataId : " + dataId + " rawContactId :"  + rawContactId +
474                                " contactId : " + contactId
475                                + " phoneNumber :" + phoneNumber + " displayName :" + displayName);
476                         verifyInsertOrUpdateAction(dataId, contactId, rawContactId, phoneNumber,
477                               displayName);
478                         if (uniqueRawContactIds.isEmpty()) {
479                             uniqueRawContactIds.add(rawContactId);
480                         } else if (!uniqueRawContactIds.contains(rawContactId)) {
481                             uniqueRawContactIds.add(rawContactId);
482                         } else {
483                             // Do nothing.
484                             logger.debug("uniqueRawContactIds already contains rawContactId : " +
485                                     rawContactId);
486                         }
487                     }
488                     checkForPhoneNumberDelete(uniqueRawContactIds);
489                     // Save the largest timestamp returned. Only need the first one due to
490                     // the sort order.
491                     cursor.moveToFirst();
492                     long timestamp = cursor.getLong(cursor
493                             .getColumnIndex(ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP));
494                     if (timestamp > 0) {
495                         SharedPrefUtil.saveLastContactChangedTimestamp(mContext, timestamp);
496                     }
497                 }
498             } else {
499                 logger.error("cursor is null!");
500             }
501         } catch (Exception e) {
502             logger.error("checkForContactNumberChanges() exception:", e);
503         } finally {
504             if (null != cursor) {
505                 cursor.close();
506             }
507         }
508         logger.debug("Exit: checkForContactNumberChanges()");
509     }
510 
verifyInsertOrUpdateAction(Long dataId, Long contactId, Long rawContactId, String phoneNumber, String displayName)511     private void verifyInsertOrUpdateAction(Long dataId, Long contactId,
512             Long rawContactId, String phoneNumber, String displayName) {
513         logger.debug("Enter: verifyInsertOrUpdateAction() phoneNumber : " + phoneNumber);
514         if (null == phoneNumber){
515             logger.error("Error: return as phoneNumber is null");
516             return;
517         }
518         // Check if the contact is already available in EAB Provider.
519         String[] eabProjection = new String[] {
520                 EABContract.EABColumns.CONTACT_NUMBER,
521                 EABContract.EABColumns.CONTACT_NAME };
522         String eabWhereClause = EABContract.EABColumns.DATA_ID + " ='" + dataId.toString()
523                 + "' AND " + EABContract.EABColumns.RAW_CONTACT_ID + " ='"
524                 + rawContactId.toString() + "' AND " + EABContract.EABColumns.CONTACT_ID
525                 + " ='" + contactId.toString() + "'";
526         logger.debug("eabWhereClause : " + eabWhereClause);
527 
528         Cursor eabCursor = getContentResolver().query(EABContract.EABColumns.CONTENT_URI,
529                 eabProjection, eabWhereClause, null, null);
530         if (null != eabCursor) {
531             int eabCursorCount = eabCursor.getCount();
532             logger.debug("EAB cursor count : " + eabCursorCount);
533             if (eabCursorCount > 0) {
534                 while (eabCursor.moveToNext()) {
535                     // EABProvider has entry for dataId & rawContactId. Try to
536                     // match the contact number.
537                     String eabPhoneNumber = eabCursor.getString(eabCursor
538                                     .getColumnIndex(EABContract.EABColumns.CONTACT_NUMBER));
539                     String eabDisplayName = eabCursor.getString(eabCursor
540                             .getColumnIndex(EABContract.EABColumns.CONTACT_NAME));
541                     logger.debug("phoneNumber : " + phoneNumber
542                             + " eabPhoneNumber :" + eabPhoneNumber);
543                     // If contact number do not match, then update EAB database with the new
544                     // number. If contact name do not match, then update EAB database with the
545                     // new name.
546                     if (null != eabPhoneNumber) {
547                         if (!phoneNumber.equals(eabPhoneNumber)) {
548                             // Update use-case.
549                             handlePhoneNumberChanged(dataId, contactId, rawContactId,
550                                     eabPhoneNumber, phoneNumber, displayName);
551                         } else if (!TextUtils.equals(displayName, eabDisplayName)) {
552                             // Update name use-case.
553                             handlePhoneNameUpdate(dataId, contactId, rawContactId,
554                                     phoneNumber, displayName);
555                         } else {
556                             // Do nothing.
557                             logger.debug("The contact name and number is already available " +
558                                     "in EAB Provider.");
559                         }
560                     }
561                 }
562             } else {
563                 // insert use-case.
564                 handlePhoneNumberInsertion(dataId, contactId, rawContactId, phoneNumber,
565                         displayName);
566             }
567         }
568         if (null != eabCursor) {
569             eabCursor.close();
570         }
571         logger.debug("Exit: verifyInsertOrUpdateAction()");
572     }
573 
checkForPhoneNumberDelete(ArrayList<Long> uniqueRawContactIds)574     private void checkForPhoneNumberDelete(ArrayList<Long> uniqueRawContactIds) {
575         logger.debug("Enter: checkForPhoneNumberDelete() ");
576         if (null != uniqueRawContactIds && uniqueRawContactIds.size() > 0) {
577             for (int i = 0; i < uniqueRawContactIds.size(); i++) {
578                 Long rawContactId = uniqueRawContactIds.get(i);
579                 int contactsDbCount = 0;
580                 int eabDbCursorCount = 0;
581 
582                 // Find the total number of dataIds under the rawContactId in
583                 // Contacts Provider DB.
584                 String[] projection = new String[] { ContactsContract.Data._ID,
585                         ContactsContract.Data.CONTACT_ID,
586                         ContactsContract.Data.RAW_CONTACT_ID,
587                         ContactsContract.Data.MIMETYPE,
588                         ContactsContract.Data.DATA1,
589                         ContactsContract.Data.DISPLAY_NAME };
590 
591                 // Get LastContactChangedTimestamp for knowing which contact
592                 // number deleted from the contact id.
593                 long contactLastChange = SharedPrefUtil.getLastContactChangedTimestamp(
594                         mContext, 0);
595 
596                 String selection = ContactsContract.Data.MIMETYPE + " = '"
597                         + Phone.CONTENT_ITEM_TYPE + "' AND " +
598                         ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP
599                         + " > '" + contactLastChange + "' AND " +
600                         ContactsContract.Data.RAW_CONTACT_ID + " = '"
601                         + rawContactId + "'";
602 
603                 String sortOrder = ContactsContract.Data.RAW_CONTACT_ID + " desc";
604 
605                 Cursor contactDbCursor = getContentResolver().query(
606                         ContactsContract.Data.CONTENT_URI, projection,
607                         selection, null, sortOrder);
608 
609                 if (null != contactDbCursor) {
610                     contactsDbCount = contactDbCursor.getCount();
611                     logger.debug("contactDbCursor count : " + contactsDbCount);
612                 }
613 
614                 // Find the total number of dataIds under the rawContactId in
615                 // EAB Provider DB.
616                 String[] eabProjection = new String[] {
617                         EABContract.EABColumns.CONTACT_ID,
618                         EABContract.EABColumns.RAW_CONTACT_ID,
619                         EABContract.EABColumns.DATA_ID,
620                         EABContract.EABColumns.CONTACT_NUMBER,
621                         EABContract.EABColumns.CONTACT_NAME };
622 
623                 String eabWhereClause = EABContract.EABColumns.RAW_CONTACT_ID
624                         + " ='" + rawContactId.toString() + "'";
625 
626                 Cursor eabDbCursor = getContentResolver().query(
627                         EABContract.EABColumns.CONTENT_URI, eabProjection,
628                         eabWhereClause, null, null);
629                 if (null != eabDbCursor) {
630                     eabDbCursorCount = eabDbCursor.getCount();
631                     logger.debug("eabDbCursor count : " + eabDbCursorCount);
632                 }
633                 if (0 == contactsDbCount && 0 == eabDbCursorCount) {
634                     // Error scenario. Continue for checking the next rawContactId.
635                     logger.error("Both cursor counts are 0. move to next rawContactId");
636                 } else {
637                     if (contactsDbCount == eabDbCursorCount) {
638                         // Do nothing as both DB have the same number of contacts.
639                         logger.debug("Both the databases have the same number of contacts." +
640                                 " Do nothing.");
641                     } else if (contactsDbCount > eabDbCursorCount) {
642                         logger.error("EAB DB has less contacts then Contacts DB. Do nothing!");
643                     } else if (contactsDbCount < eabDbCursorCount) {
644                         // find and number and delete it from EAB Provider.
645                         logger.debug("Delete usecase hit. Find and delete contact from EAB DB.");
646                         ArrayList <Long> eabDataIdList = new ArrayList <Long>();
647                         while (eabDbCursor.moveToNext()) {
648                             String eabPhoneNumber = eabDbCursor.getString(eabDbCursor
649                                     .getColumnIndex(EABContract.EABColumns.CONTACT_NUMBER));
650                             logger.debug("eabPhoneNumber :" + eabPhoneNumber);
651                             Long eabDataId = Long.valueOf(eabDbCursor.getLong(eabDbCursor
652                                     .getColumnIndex(EABContract.EABColumns.DATA_ID)));
653                             logger.debug("eabDataId :" + eabDataId);
654                             if (eabDataIdList.isEmpty()) {
655                                 eabDataIdList.add(eabDataId);
656                             } else if (!eabDataIdList.contains(eabDataId) )  {
657                                 eabDataIdList.add(eabDataId);
658                             } else {
659                                 // Something is wrong. There can not be duplicate numbers.
660                                 logger.error("Duplicate entry for PhoneNumber :" + eabPhoneNumber
661                                         + " with DataId : " + eabDataId + " found in EABProvider.");
662                             }
663                         }
664                         logger.debug("Before computation eabDataIdList size :" +
665                                 eabDataIdList.size());
666                         while (contactDbCursor.moveToNext()) {
667                             String contactPhoneNumber = contactDbCursor.getString(contactDbCursor
668                                     .getColumnIndex(ContactsContract.Data.DATA1));
669                             Long contactDataId = Long.valueOf(contactDbCursor.getLong(
670                                     contactDbCursor
671                                             .getColumnIndex(ContactsContract.Data._ID)));
672                             logger.debug("contactPhoneNumber : " + contactPhoneNumber +
673                                     " dataId : " + contactDataId);
674                             if (eabDataIdList.contains(contactDataId) )  {
675                                 eabDataIdList.remove(contactDataId);
676                                 logger.debug("Number removed from eabDataIdList");
677                             } else {
678                                 // Something is wrong. There can not be new number in Contacts DB.
679                                 logger.error("Number :" + contactPhoneNumber
680                                         + " with DataId : " + contactDataId +
681                                         " not found in EABProvider.");
682                             }
683                         }
684                         logger.debug("After computation eabPhoneNumberList size :" +
685                                 eabDataIdList.size());
686                         if (eabDataIdList.size() > 0) {
687                             handlePhoneNumbersDeleted(rawContactId, eabDataIdList);
688                         }
689                     }
690                 }
691                 if (null != contactDbCursor) {
692                     contactDbCursor.close();
693                 }
694                 if (null != eabDbCursor) {
695                     eabDbCursor.close();
696                 }
697             }
698         } else {
699             // Do nothing.
700             logger.debug("uniqueRawContactIds is null or empty. Do nothing. ");
701         }
702         logger.debug("Exit: checkForPhoneNumberDelete() ");
703     }
704 
checkForDeletedContact()705     private void checkForDeletedContact() {
706         logger.debug("Enter: checkForDeletedContact()");
707         String[] projection = new String[] {
708                 ContactsContract.DeletedContacts.CONTACT_ID,
709                 ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP };
710 
711         long contactLastDeleted = SharedPrefUtil.getLastContactDeletedTimestamp(mContext, 0);
712         logger.debug("contactLastDeleted : " + contactLastDeleted);
713 
714         String selection = ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP
715                 + " > '" + contactLastDeleted + "'";
716 
717         String sortOrder = ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP + " desc";
718 
719         Cursor cursor = getContentResolver().query(
720                 ContactsContract.DeletedContacts.CONTENT_URI, projection,
721                 selection, null, sortOrder);
722         if (null != cursor) {
723             int count = cursor.getCount();
724             logger.debug("cursor count : " + count);
725             if (count > 0) {
726                 while (cursor.moveToNext()) {
727                     Long contactId = Long.valueOf(cursor.getLong(cursor
728                                     .getColumnIndex(ContactsContract.DeletedContacts.CONTACT_ID)));
729                     logger.debug("contactId : " + contactId);
730                     handleContactDeleted(contactId);
731                 }
732                 // Save the largest returned timestamp. Only need the first
733                 // cursor element due to the sort order.
734                 cursor.moveToFirst();
735                 long timestamp = cursor.getLong(cursor
736                         .getColumnIndex(
737                         ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP));
738                 if (timestamp > 0) {
739                     SharedPrefUtil.saveLastContactDeletedTimestamp(mContext, timestamp);
740                 }
741             }
742         }
743         if (null != cursor) {
744             cursor.close();
745         }
746         logger.debug("Exit: checkForDeletedContact()");
747     }
748 
checkForProfileNumberChanges()749     private void checkForProfileNumberChanges() {
750         logger.debug("Enter: checkForProfileNumberChanges()");
751         String[] projection = new String[] {
752                 ContactsContract.Contacts.Entity.CONTACT_ID,
753                 ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
754                 ContactsContract.Contacts.Entity.DATA_ID,
755                 ContactsContract.Contacts.Entity.MIMETYPE,
756                 ContactsContract.Contacts.Entity.DATA1,
757                 ContactsContract.Contacts.Entity.DISPLAY_NAME,
758                 ContactsContract.Contacts.Entity.CONTACT_LAST_UPDATED_TIMESTAMP};
759 
760         long profileContactLastChange = SharedPrefUtil.getLastProfileContactChangedTimestamp(
761                 mContext, 0);
762         logger.debug("profileContactLastChange : " + profileContactLastChange);
763 
764         String selection = ContactsContract.Contacts.Entity.MIMETYPE + " ='" +
765                 Phone.CONTENT_ITEM_TYPE + "' AND "
766                 + ContactsContract.Contacts.Entity.CONTACT_LAST_UPDATED_TIMESTAMP  + " > '" +
767                 profileContactLastChange + "'";
768         String sortOrder = ContactsContract.Contacts.Entity.CONTACT_LAST_UPDATED_TIMESTAMP +
769                 " desc";
770         // Construct the Uri to access Profile's Entity view.
771         Uri profileUri = ContactsContract.Profile.CONTENT_URI;
772         Uri entiryUri = Uri.withAppendedPath(profileUri,
773                 ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
774 
775         Cursor cursor = getContentResolver().query(entiryUri, projection, selection, null,
776                 sortOrder);
777         if (null != cursor) {
778             int count = cursor.getCount();
779             logger.debug("cursor count : " + count);
780             if (count > 0) {
781                 ArrayList <String> profileNumberList = new ArrayList <String>();
782                 ArrayList <Long> profileDataIdList = new ArrayList <Long>();
783                 Long contactId = null;
784                 Long rawContactId = null;
785                 while (cursor.moveToNext()) {
786                     contactId = Long.valueOf(cursor.getLong(cursor.getColumnIndex(
787                             ContactsContract.Contacts.Entity.CONTACT_ID)));
788                     rawContactId = Long.valueOf(cursor.getLong(cursor.getColumnIndex(
789                             ContactsContract.Contacts.Entity.RAW_CONTACT_ID)));
790                     Long dataId = Long.valueOf(cursor.getLong(cursor.getColumnIndex(
791                             ContactsContract.Contacts.Entity.DATA_ID)));
792                     String contactNumber = cursor.getString(cursor.getColumnIndex(
793                             ContactsContract.Contacts.Entity.DATA1));
794                     String profileName = cursor.getString(cursor.getColumnIndex(
795                             ContactsContract.Contacts.Entity.DISPLAY_NAME));
796                     logger.debug("Profile Name : " + profileName
797                             + " Profile Number : " + contactNumber
798                             + " profile dataId : " + dataId
799                             + " profile rawContactId : " + rawContactId
800                             + " profile contactId : " + contactId);
801                     if (profileDataIdList.isEmpty()) {
802                         profileDataIdList.add(dataId);
803                         profileNumberList.clear();
804                         profileNumberList.add(contactNumber);
805                     } else if (!profileDataIdList.contains(dataId)) {
806                         profileDataIdList.add(dataId);
807                         profileNumberList.add(contactNumber);
808                     } else {
809                         // There are duplicate entries in Profile's Table
810                         logger.error("Duplicate entry in Profile's Table for contact :" +
811                                 contactNumber + " dataId : " + dataId);
812                     }
813                     verifyInsertOrUpdateAction(dataId, contactId, rawContactId, contactNumber,
814                             profileName);
815                 }
816                 checkForProfilePhoneNumberDelete(contactId, rawContactId, profileDataIdList);
817                 // Save the largest timestamp returned. Only need the first cursor element
818                 // due to sort order.
819                 cursor.moveToFirst();
820                 long timestamp = cursor.getLong(cursor.getColumnIndex(
821                         ContactsContract.Contacts.Entity.CONTACT_LAST_UPDATED_TIMESTAMP));
822                 if (timestamp > 0) {
823                     SharedPrefUtil.saveLastProfileContactChangedTimestamp(mContext, timestamp);
824                 }
825             } else {
826                 logger.error("cursor is zero. Do nothing.");
827             }
828         } else {
829             logger.error("ContactsContract.Profile.CONTENT_URI cursor is null!");
830         }
831         if (null != cursor) {
832             cursor.close();
833         }
834         logger.debug("Exit: checkForProfileNumberChanges()");
835     }
836 
checkForProfilePhoneNumberDelete(Long profileContactId, Long profileRawContactId, ArrayList<Long> profileDataIdList)837     private void checkForProfilePhoneNumberDelete(Long profileContactId,
838             Long profileRawContactId, ArrayList<Long> profileDataIdList) {
839         logger.debug("Enter: checkForProfilePhoneNumberDelete()");
840         if (!ContactsContract.isProfileId(profileContactId)) {
841             logger.error("Not a Profile Contact Id : " + profileContactId);
842             return;
843         }
844         int eabDbCursorCount = 0;
845         int profileContactsDbCount = profileDataIdList.size();
846         logger.error("profileContactsDbCount size : " + profileContactsDbCount);
847         // Find the total number of dataIds under the rawContactId in EAB Provider DB.
848         String[] eabProjection = new String[] {
849                 EABContract.EABColumns.CONTACT_ID,
850                 EABContract.EABColumns.DATA_ID,
851                 EABContract.EABColumns.CONTACT_NUMBER};
852         String eabWhereClause = EABContract.EABColumns.CONTACT_ID + " ='" +
853                 profileContactId.toString() + "'";
854 
855         Cursor eabDbCursor = getContentResolver().query( EABContract.EABColumns.CONTENT_URI,
856                 eabProjection,
857                 eabWhereClause, null, null);
858         if (null != eabDbCursor) {
859             eabDbCursorCount = eabDbCursor.getCount();
860             logger.debug("eabDbCursor count : " + eabDbCursorCount);
861         }
862         if (0 == profileContactsDbCount && 0 == eabDbCursorCount) {
863             // Error scenario. Continue for checking the next rawContactId.
864             logger.error("Both cursor counts are 0. Do nothing");
865         } else {
866             if (profileContactsDbCount == eabDbCursorCount) {
867                 // Do nothing as both DB have the same number of contacts.
868                 logger.debug("Both the databases have the same number of contacts. Do nothing.");
869             } else if (profileContactsDbCount > eabDbCursorCount) {
870                 logger.error("EAB DB has less contacts then Contacts DB. Do nothing!");
871             } else if (profileContactsDbCount < eabDbCursorCount) {
872                 // find and number and delete it from EAB Provider.
873                 logger.debug("Delete usecase hit. Find and delete contact from EAB DB.");
874                 ArrayList <Long> eabDataIdList = new ArrayList <Long>();
875                 while (eabDbCursor.moveToNext()) {
876                     Long eabDataId = Long.valueOf(eabDbCursor.getLong(eabDbCursor
877                                     .getColumnIndex(EABContract.EABColumns.DATA_ID)));
878                     logger.debug("eabDataId : " + eabDataId);
879                     if (eabDataIdList.isEmpty()) {
880                         eabDataIdList.add(eabDataId);
881                     } else if (!eabDataIdList.contains(eabDataId) )  {
882                         eabDataIdList.add(eabDataId);
883                     } else {
884                         // Something is wrong. There can not be duplicate numbers.
885                         logger.error("Duplicate entry for eabDataId in EABProvider : " +
886                                 eabDataId);
887                     }
888                 }
889                 logger.debug("Before computation eabDataIdList size : " + eabDataIdList.size());
890                 for (int i = 0; i < profileDataIdList.size(); i++) {
891                     Long contactDataId = profileDataIdList.get(i);
892                     logger.debug("Profile contactDataId : " + contactDataId);
893                     if (eabDataIdList.contains(contactDataId) )  {
894                         eabDataIdList.remove(contactDataId);
895                         logger.debug("Number removed from eabDataIdList");
896                     } else {
897                         // Something is wrong. There can not be new number in Contacts DB.
898                         logger.error("DataId : " + contactDataId +
899                                 " not found in EAB Provider DB.");
900                     }
901                 }
902                 logger.debug("After computation eabDataIdList size : " + eabDataIdList.size());
903                 if (eabDataIdList.size() > 0) {
904                     handlePhoneNumbersDeleted(profileRawContactId, eabDataIdList);
905                 }
906             }
907         }
908         if (null != eabDbCursor) {
909             eabDbCursor.close();
910         }
911         logger.debug("Exit: checkForProfilePhoneNumberDelete() ");
912     }
913 
checkForDeletedProfileContacts()914     private void checkForDeletedProfileContacts() {
915         logger.debug("Enter: checkForDeletedProfileContacts()");
916         String[] projection = new String[] {
917                 ContactsContract.Contacts.Entity.DATA1,
918                 ContactsContract.Contacts.Entity.DISPLAY_NAME,
919                 ContactsContract.Contacts.Entity.CONTACT_LAST_UPDATED_TIMESTAMP};
920 
921         String selection = ContactsContract.Contacts.Entity.MIMETYPE + " ='" +
922                 Phone.CONTENT_ITEM_TYPE + "'";
923         // Construct the Uri to access Profile's Entity view.
924         Uri profileUri = ContactsContract.Profile.CONTENT_URI;
925         Uri entiryUri = Uri.withAppendedPath(profileUri,
926                 ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
927 
928         // Due to issue in AOSP contact profile db, table
929         // ContactsContract.Profile.CONTENT_URI can not be checked for
930         // selection = ContactsContract.Profile.HAS_PHONE_NUMBER + " = '" + 1 + "'".
931         // This is resulting in 0 cursor count even when there are valid
932         // contact numbers under contacts profile db.
933         Cursor cursor = getContentResolver().query(entiryUri, projection, selection, null, null);
934         if (null != cursor) {
935             int count = cursor.getCount();
936             logger.debug("Profile contact cursor count : " + count);
937             if (count == 0) {
938                 logger.debug("cursor count is Zero. There are no contacts in Contact Profile db.");
939                 handleContactProfileDeleted();
940             } else {
941                 logger.debug("Profile is available. Do nothing");
942             }
943             cursor.close();
944         }
945         logger.debug("Exit: checkForDeletedProfileContacts()");
946     }
947 
handlePhoneNumberInsertion(Long dataId, Long contactId, Long rawContactId, String phoneNumber, String contactName)948     private void handlePhoneNumberInsertion(Long dataId, Long contactId,
949             Long rawContactId, String phoneNumber, String contactName) {
950 
951         logger.debug("handlePhoneNumberInsertion() rawContactId : "
952                 + rawContactId + " dataId :" + dataId + " contactId :"
953                 + contactId + " phoneNumber :" + phoneNumber + " contactName :"
954                 + contactName);
955         if (!EABDbUtil.validateEligibleContact(mContext, phoneNumber)) {
956             logger.debug("Return as number is not elegible for VT.");
957             return;
958         }
959         String sRawContactId = null;
960         String sDataId = null;
961         String sContactId = null;
962         if (null != rawContactId) {
963             sRawContactId = rawContactId.toString();
964         }
965         if (null != dataId) {
966             sDataId = dataId.toString();
967         }
968         if (null != contactId) {
969             sContactId = contactId.toString();
970         }
971         String formattedNumber = EABDbUtil.formatNumber(phoneNumber);
972         ArrayList<PresenceContact> contactListToInsert = new ArrayList<PresenceContact>();
973         contactListToInsert.add(new PresenceContact(contactName, phoneNumber, formattedNumber,
974                 sRawContactId, sContactId, sDataId));
975 
976         EABDbUtil.addContactsToEabDb(getApplicationContext(),
977                 contactListToInsert);
978     }
979 
handlePhoneNumberChanged(Long dataId, Long contactId, Long rawContactId, String oldPhoneNumber, String newPhoneNumber, String contactName)980     private void handlePhoneNumberChanged(Long dataId, Long contactId,
981             Long rawContactId, String oldPhoneNumber, String newPhoneNumber,
982             String contactName) {
983 
984         logger.debug("handlePhoneNumberChanged() rawContactId : " + rawContactId
985                 + " dataId :" + dataId + " oldPhoneNumber :" + oldPhoneNumber
986                 + " newPhoneNumber :" + newPhoneNumber + " contactName :"
987                 + contactName);
988 
989         if (null == oldPhoneNumber && null == newPhoneNumber) {
990             logger.debug("Both old and new numbers are null.");
991             return;
992         }
993 
994         ArrayList<PresenceContact> contactListToInsert = new ArrayList<PresenceContact>();
995         ArrayList<PresenceContact> contactListToDelete = new ArrayList<PresenceContact>();
996         String sRawContactId = null;
997         String sDataId = null;
998         String sContactId = null;
999         if (null != rawContactId) {
1000             sRawContactId = rawContactId.toString();
1001         }
1002         if (null != dataId) {
1003             sDataId = dataId.toString();
1004         }
1005         if (null != contactId) {
1006             sContactId = contactId.toString();
1007         }
1008         String newFormattedNumber = EABDbUtil.formatNumber(newPhoneNumber);
1009         logger.debug("newFormattedNumber : " + newFormattedNumber);
1010         logger.debug("Removing old number and inserting new number in EABProvider.");
1011         if (null != oldPhoneNumber) {
1012             contactListToDelete.add(new PresenceContact(contactName,
1013                     oldPhoneNumber, null /*formattedNumber*/, sRawContactId, sContactId, sDataId));
1014             // Delete old number from EAB Presence Table
1015             EABDbUtil.deleteNumbersFromEabDb(getApplicationContext(), contactListToDelete);
1016         }
1017         if (null != newPhoneNumber) {
1018             if (EABDbUtil.validateEligibleContact(mContext, newPhoneNumber)) {
1019                 contactListToInsert.add(new PresenceContact(contactName,
1020                         newPhoneNumber, newFormattedNumber, sRawContactId, sContactId, sDataId));
1021                 // Insert new number from EAB Presence Table
1022                 EABDbUtil.addContactsToEabDb(getApplicationContext(), contactListToInsert);
1023             } else {
1024                 logger.debug("Return as number is not elegible for VT.");
1025             }
1026         }
1027     }
1028 
handlePhoneNumbersDeleted(Long rawContactId, ArrayList <Long> contactDataIdList)1029     private void handlePhoneNumbersDeleted(Long rawContactId, ArrayList <Long> contactDataIdList) {
1030         ArrayList<PresenceContact> phoneNumberToDeleteList = new ArrayList<PresenceContact>();
1031         for (int v = 0; v < contactDataIdList.size(); v++) {
1032             Long staleDataId = contactDataIdList.get(v);
1033             if (null != staleDataId) {
1034                 logger.debug("calling delete for staleNumber :" + staleDataId);
1035                 String sRawContactId = null;
1036                 if (null != rawContactId) {
1037                     sRawContactId = rawContactId.toString();
1038                 }
1039                 phoneNumberToDeleteList.add(new PresenceContact(null, null, null,
1040                         sRawContactId, null, staleDataId.toString()));
1041             }
1042         }
1043         // Delete number from EAB Provider table.
1044         EABDbUtil.deleteNumbersFromEabDb(getApplicationContext(), phoneNumberToDeleteList);
1045     }
1046 
handlePhoneNameUpdate(Long dataId, Long contactId, Long rawContactId, String phoneNumber, String newDisplayName)1047     private void handlePhoneNameUpdate(Long dataId, Long contactId,
1048             Long rawContactId, String phoneNumber, String newDisplayName) {
1049         logger.debug("handlePhoneNameUpdate() rawContactId : " + rawContactId
1050                 + " dataId :" + dataId + " newDisplayName :" + newDisplayName);
1051         String sRawContactId = null;
1052         String sDataId = null;
1053         String sContactId = null;
1054         if (null != rawContactId) {
1055             sRawContactId = rawContactId.toString();
1056         }
1057         if (null != dataId) {
1058             sDataId = dataId.toString();
1059         }
1060         if (null != contactId) {
1061             sContactId = contactId.toString();
1062         }
1063         ArrayList<PresenceContact> contactNameToUpdate = new ArrayList<PresenceContact>();
1064         contactNameToUpdate.add(new PresenceContact(newDisplayName,
1065                 phoneNumber, null /*formattedNumber */, sRawContactId, sContactId, sDataId));
1066 
1067         EABDbUtil.updateNamesInEabDb(getApplicationContext(), contactNameToUpdate);
1068     }
1069 
handleContactDeleted(Long contactId)1070     private void handleContactDeleted(Long contactId) {
1071 
1072         if (null == contactId) {
1073             logger.debug("handleContactDeleted : contactId is null");
1074         }
1075         ArrayList<PresenceContact> contactListToDelete = new ArrayList<PresenceContact>();
1076         contactListToDelete.add(new PresenceContact(null, null, null, null, contactId.toString(),
1077                 null));
1078 
1079         //ContactDbUtil.deleteRawContact(getApplicationContext(), contactListToDelete);
1080         EABDbUtil.deleteContactsFromEabDb(mContext, contactListToDelete);
1081     }
1082 
handleContactProfileDeleted()1083     private void handleContactProfileDeleted() {
1084         Long contactProfileMinId = Long.valueOf(ContactsContract.Profile.MIN_ID);
1085         logger.debug("contactProfileMinId : " + contactProfileMinId);
1086 
1087         ArrayList<PresenceContact> contactListToDelete = new ArrayList<PresenceContact>();
1088         contactListToDelete.add(new PresenceContact(null, null, null, null,
1089                 contactProfileMinId.toString(), null));
1090 
1091         EABDbUtil.deleteContactsFromEabDb(mContext, contactListToDelete);
1092     }
1093 }
1094