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