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