ContactsContentObserver.java revision 4084fa5caeee09ef7993957c5e922dab14c57f3f
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.inputmethod.latin; 18 19import android.content.ContentResolver; 20import android.content.Context; 21import android.database.ContentObserver; 22import android.os.SystemClock; 23import android.provider.ContactsContract.Contacts; 24import android.util.Log; 25 26import com.android.inputmethod.annotations.UsedForTesting; 27import com.android.inputmethod.latin.ContactsManager.ContactsChangedListener; 28import com.android.inputmethod.latin.utils.ExecutorUtils; 29 30import java.util.ArrayList; 31import java.util.concurrent.ExecutorService; 32 33/** 34 * A content observer that listens to updates to content provider {@link Contacts.CONTENT_URI}. 35 */ 36// TODO:add test 37public class ContactsContentObserver { 38 private static final String TAG = ContactsContentObserver.class.getSimpleName(); 39 private static final boolean DEBUG = false; 40 41 private ContentObserver mObserver; 42 43 private final Context mContext; 44 private final ContactsManager mManager; 45 46 public ContactsContentObserver(final ContactsManager manager, final Context context) { 47 mManager = manager; 48 mContext = context; 49 } 50 51 public void registerObserver(final ContactsChangedListener listener) { 52 if (DEBUG) { 53 Log.d(TAG, "Registered Contacts Content Observer"); 54 } 55 mObserver = new ContentObserver(null /* handler */) { 56 @Override 57 public void onChange(boolean self) { 58 getBgExecutor().execute(new Runnable() { 59 @Override 60 public void run() { 61 if (haveContentsChanged()) { 62 if (DEBUG) { 63 Log.d(TAG, "Contacts have changed; notifying listeners"); 64 } 65 listener.onContactsChange(); 66 } 67 } 68 }); 69 } 70 }; 71 final ContentResolver contentResolver = mContext.getContentResolver(); 72 contentResolver.registerContentObserver(Contacts.CONTENT_URI, true, mObserver); 73 } 74 75 @UsedForTesting 76 private ExecutorService getBgExecutor() { 77 return ExecutorUtils.getExecutor("Check Contacts"); 78 } 79 80 private boolean haveContentsChanged() { 81 final long startTime = SystemClock.uptimeMillis(); 82 final int contactCount = mManager.getContactCount(); 83 if (contactCount > ContactsDictionaryConstants.MAX_CONTACT_COUNT) { 84 // If there are too many contacts then return false. In this rare case it is impossible 85 // to include all of them anyways and the cost of rebuilding the dictionary is too high. 86 // TODO: Sort and check only the MAX_CONTACT_COUNT most recent contacts? 87 return false; 88 } 89 if (contactCount != mManager.getContactCountAtLastRebuild()) { 90 if (DEBUG) { 91 Log.d(TAG, "Contact count changed: " + mManager.getContactCountAtLastRebuild() 92 + " to " + contactCount); 93 } 94 return true; 95 } 96 final ArrayList<String> names = mManager.getValidNames(Contacts.CONTENT_URI); 97 if (names.hashCode() != mManager.getHashCodeAtLastRebuild()) { 98 return true; 99 } 100 if (DEBUG) { 101 Log.d(TAG, "No contacts changed. (runtime = " + (SystemClock.uptimeMillis() - startTime) 102 + " ms)"); 103 } 104 return false; 105 } 106 107 public void unregister() { 108 mContext.getContentResolver().unregisterContentObserver(mObserver); 109 } 110} 111