1f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov/*
2f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project
3f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov *
4f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
5f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * you may not use this file except in compliance with the License.
6f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * You may obtain a copy of the License at
7f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov *
8f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
9f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov *
10f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
11f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
12f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * See the License for the specific language governing permissions and
14f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * limitations under the License
15f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */
16f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
19f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.content.ContentResolver;
20f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.content.Context;
21d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikovimport android.database.ContentObserver;
22f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.database.Cursor;
23f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.net.Uri;
24f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.os.Handler;
25f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.os.HandlerThread;
26f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.os.Message;
27f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.os.Process;
28f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
29f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
30f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
31f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo;
32f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
33f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
34f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions;
35f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder;
36f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Data;
37c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
38f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.text.TextUtils;
39f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
40851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDelta.ValuesDelta;
41e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
42e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
43f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.ArrayList;
44f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.Arrays;
45f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
46f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
47f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov/**
48f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Runs asynchronous queries to obtain aggregation suggestions in the as-you-type mode.
49f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */
50f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovpublic class AggregationSuggestionEngine extends HandlerThread {
51f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public static final String TAG = "AggregationSuggestionEngine";
52f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
53f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public interface Listener {
54f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        void onAggregationSuggestionChange();
55f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
56f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
57c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov    public static final class RawContact {
58c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public long rawContactId;
59c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public String accountType;
60c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public String accountName;
612b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        public String dataSet;
62c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov
63c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        @Override
64c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public String toString() {
652b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            return "ID: " + rawContactId + " account: " + accountType + "/" + accountName
662b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    + " dataSet: " + dataSet;
67c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        }
68c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov    }
69c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov
70f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public static final class Suggestion {
71c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov
72f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public long contactId;
73f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public String lookupKey;
74f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public String name;
75f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public String phoneNumber;
76f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public String emailAddress;
77f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public String nickname;
78f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public byte[] photo;
79c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public List<RawContact> rawContacts;
80f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
81f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        @Override
82f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public String toString() {
83c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            return "ID: " + contactId + " rawContacts: " + rawContacts + " name: " + name
84d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            + " phone: " + phoneNumber + " email: " + emailAddress + " nickname: "
85d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            + nickname + (photo != null ? " [has photo]" : "");
86d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        }
87d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    }
88d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
89d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private final class SuggestionContentObserver extends ContentObserver {
90d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        private SuggestionContentObserver(Handler handler) {
91d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            super(handler);
92d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        }
93d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
94d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        @Override
95d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        public void onChange(boolean selfChange) {
96d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            scheduleSuggestionLookup();
97f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
98f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
99f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
100d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private static final int MESSAGE_RESET = 0;
101d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private static final int MESSAGE_NAME_CHANGE = 1;
102d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private static final int MESSAGE_DATA_CURSOR = 2;
103d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
104d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private static final long SUGGESTION_LOOKUP_DELAY_MILLIS = 300;
105d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
106d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private static final int MAX_SUGGESTION_COUNT = 3;
107d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
108d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private final Context mContext;
109d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
110d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private long[] mSuggestedContactIds = new long[0];
111d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
112d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private Handler mMainHandler;
113d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private Handler mHandler;
114d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private long mContactId;
115d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private Listener mListener;
116d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private Cursor mDataCursor;
117d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private ContentObserver mContentObserver;
118d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    private Uri mSuggestionsUri;
119d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
120f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public AggregationSuggestionEngine(Context context) {
121f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super("AggregationSuggestions", Process.THREAD_PRIORITY_BACKGROUND);
1222828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki        mContext = context.getApplicationContext();
123f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mMainHandler = new Handler() {
124f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            @Override
125f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            public void handleMessage(Message msg) {
126f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                AggregationSuggestionEngine.this.deliverNotification((Cursor) msg.obj);
127f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
128f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        };
129f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
130f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
131f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected Handler getHandler() {
132f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mHandler == null) {
133f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mHandler = new Handler(getLooper()) {
134f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                @Override
135f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                public void handleMessage(Message msg) {
136f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    AggregationSuggestionEngine.this.handleMessage(msg);
137f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
138f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            };
139f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
140f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return mHandler;
141f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
142f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
143f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void setContactId(long contactId) {
144916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        if (contactId != mContactId) {
145916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov            mContactId = contactId;
146916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov            reset();
147916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        }
148f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
149f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
150f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void setListener(Listener listener) {
151f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mListener = listener;
152f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
153f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
154f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
155f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public boolean quit() {
156f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mDataCursor != null) {
157f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mDataCursor.close();
158f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
159f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mDataCursor = null;
160d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        if (mContentObserver != null) {
161d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            mContext.getContentResolver().unregisterContentObserver(mContentObserver);
162d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            mContentObserver = null;
163d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        }
164f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return super.quit();
165f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
166f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1679302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    public void reset() {
1689302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        Handler handler = getHandler();
1699302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        handler.removeMessages(MESSAGE_NAME_CHANGE);
1709302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        handler.sendEmptyMessage(MESSAGE_RESET);
1719302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
1729302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
173f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onNameChange(ValuesDelta values) {
174d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        mSuggestionsUri = buildAggregationSuggestionUri(values);
175d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        if (mSuggestionsUri != null) {
176d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            if (mContentObserver == null) {
177d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov                mContentObserver = new SuggestionContentObserver(getHandler());
178d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov                mContext.getContentResolver().registerContentObserver(
179d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov                        Contacts.CONTENT_URI, true, mContentObserver);
180d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            }
181d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        } else if (mContentObserver != null) {
182d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            mContext.getContentResolver().unregisterContentObserver(mContentObserver);
183d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov            mContentObserver = null;
184d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        }
185d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        scheduleSuggestionLookup();
186d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    }
187d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov
188d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov    protected void scheduleSuggestionLookup() {
189f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Handler handler = getHandler();
190f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        handler.removeMessages(MESSAGE_NAME_CHANGE);
191f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
192d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        if (mSuggestionsUri == null) {
193f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
194f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
195f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
196d52121b61b71230d0f695f9d3891eaf0cbb7c549Dmitri Plotnikov        Message msg = handler.obtainMessage(MESSAGE_NAME_CHANGE, mSuggestionsUri);
197f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        handler.sendMessageDelayed(msg, SUGGESTION_LOOKUP_DELAY_MILLIS);
198f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
199f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
200f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private Uri buildAggregationSuggestionUri(ValuesDelta values) {
201f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        StringBuilder nameSb = new StringBuilder();
202f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(nameSb, values, StructuredName.PREFIX);
203f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(nameSb, values, StructuredName.GIVEN_NAME);
204f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(nameSb, values, StructuredName.MIDDLE_NAME);
205f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(nameSb, values, StructuredName.FAMILY_NAME);
206f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(nameSb, values, StructuredName.SUFFIX);
207f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
208c9916d303cc48b4a4ff94ef9c56d7ca5da72c4deDmitri Plotnikov        if (nameSb.length() == 0) {
209c9916d303cc48b4a4ff94ef9c56d7ca5da72c4deDmitri Plotnikov            appendValue(nameSb, values, StructuredName.DISPLAY_NAME);
210c9916d303cc48b4a4ff94ef9c56d7ca5da72c4deDmitri Plotnikov        }
211c9916d303cc48b4a4ff94ef9c56d7ca5da72c4deDmitri Plotnikov
212f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        StringBuilder phoneticNameSb = new StringBuilder();
213f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(phoneticNameSb, values, StructuredName.PHONETIC_FAMILY_NAME);
214f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(phoneticNameSb, values, StructuredName.PHONETIC_MIDDLE_NAME);
215f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        appendValue(phoneticNameSb, values, StructuredName.PHONETIC_GIVEN_NAME);
216f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
217f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (nameSb.length() == 0 && phoneticNameSb.length() == 0) {
218f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return null;
219f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
220f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
221f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Builder builder = AggregationSuggestions.builder()
222f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                .setLimit(MAX_SUGGESTION_COUNT)
223f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                .setContactId(mContactId);
224f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
225f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (nameSb.length() != 0) {
226f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            builder.addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, nameSb.toString());
227f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
228f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
229f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (phoneticNameSb.length() != 0) {
230f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            builder.addParameter(
231f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    AggregationSuggestions.PARAMETER_MATCH_NAME, phoneticNameSb.toString());
232f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
233f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
234f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return builder.build();
235f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
236f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
237f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private void appendValue(StringBuilder sb, ValuesDelta values, String column) {
238f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        String value = values.getAsString(column);
239f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (!TextUtils.isEmpty(value)) {
240f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (sb.length() > 0) {
241f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                sb.append(' ');
242f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
243f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            sb.append(value);
244f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
245f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
246f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
247f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected void handleMessage(Message msg) {
2489302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        switch (msg.what) {
2499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            case MESSAGE_RESET:
2509302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                mSuggestedContactIds = new long[0];
2519302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                break;
252f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            case MESSAGE_NAME_CHANGE:
253f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                loadAggregationSuggestions((Uri) msg.obj);
254f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                break;
255f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
256f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
257f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
258f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private static final class DataQuery {
259f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
260f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final String SELECTION_PREFIX =
261f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                Data.MIMETYPE + " IN ('"
262f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Phone.CONTENT_ITEM_TYPE + "','"
263f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Email.CONTENT_ITEM_TYPE + "','"
264f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + StructuredName.CONTENT_ITEM_TYPE + "','"
265f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Nickname.CONTENT_ITEM_TYPE + "','"
266f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Photo.CONTENT_ITEM_TYPE + "')"
267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                + " AND " + Data.CONTACT_ID + " IN (";
268f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
269f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final String[] COLUMNS = {
270f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data._ID,
271f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.CONTACT_ID,
272f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.LOOKUP_KEY,
273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.PHOTO_ID,
274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.DISPLAY_NAME,
275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.RAW_CONTACT_ID,
276f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.MIMETYPE,
277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.DATA1,
278f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.IS_SUPER_PRIMARY,
279f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Photo.PHOTO,
280c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
281c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
2822b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            RawContacts.DATA_SET
283f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        };
284f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
285f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int ID = 0;
286f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int CONTACT_ID = 1;
287f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int LOOKUP_KEY = 2;
288f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int PHOTO_ID = 3;
289f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int DISPLAY_NAME = 4;
290f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 5;
291f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int MIMETYPE = 6;
292f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int DATA1 = 7;
293f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int IS_SUPERPRIMARY = 8;
294f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int PHOTO = 9;
295c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public static final int ACCOUNT_TYPE = 10;
296c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public static final int ACCOUNT_NAME = 11;
2972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        public static final int DATA_SET = 12;
298f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
299f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
300f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private void loadAggregationSuggestions(Uri uri) {
301f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        ContentResolver contentResolver = mContext.getContentResolver();
302f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Cursor cursor = contentResolver.query(uri, new String[]{Contacts._ID}, null, null, null);
303f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        try {
304f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            // If a new request is pending, chuck the result of the previous request
305f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (getHandler().hasMessages(MESSAGE_NAME_CHANGE)) {
306f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                return;
307f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
308f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
309f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            boolean changed = updateSuggestedContactIds(cursor);
310f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (!changed) {
311f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                return;
312f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
313f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
314f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            StringBuilder sb = new StringBuilder(DataQuery.SELECTION_PREFIX);
315f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            int count = mSuggestedContactIds.length;
316f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            for (int i = 0; i < count; i++) {
317f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (i > 0) {
318f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    sb.append(',');
319f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
320f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                sb.append(mSuggestedContactIds[i]);
321f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
322f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            sb.append(')');
323f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            sb.toString();
324f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
325f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Cursor dataCursor = contentResolver.query(Data.CONTENT_URI,
326f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    DataQuery.COLUMNS, sb.toString(), null, Data.CONTACT_ID);
327f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mMainHandler.sendMessage(mMainHandler.obtainMessage(MESSAGE_DATA_CURSOR, dataCursor));
328f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        } finally {
329f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            cursor.close();
330f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
331f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
332f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
333f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private boolean updateSuggestedContactIds(Cursor cursor) {
334f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        int count = cursor.getCount();
335f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        boolean changed = count != mSuggestedContactIds.length;
336f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (!changed) {
337f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            while (cursor.moveToNext()) {
338f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                long contactId = cursor.getLong(0);
339f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (Arrays.binarySearch(mSuggestedContactIds, contactId) < 0) {
340f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    changed = true;
341f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    break;
342f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
343f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
344f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
345f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
346f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (changed) {
347f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mSuggestedContactIds = new long[count];
348f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            cursor.moveToPosition(-1);
349f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            for (int i = 0; i < count; i++) {
350f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                cursor.moveToNext();
351f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                mSuggestedContactIds[i] = cursor.getLong(0);
352f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
353f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Arrays.sort(mSuggestedContactIds);
354f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
355f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
356f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return changed;
357f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
358f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
359f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected void deliverNotification(Cursor dataCursor) {
360f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mDataCursor != null) {
361f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mDataCursor.close();
362f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
363f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mDataCursor = dataCursor;
364f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mListener != null) {
365f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mListener.onAggregationSuggestionChange();
366f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
367f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
368f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
369f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public int getSuggestedContactCount() {
3709302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return mDataCursor != null ? mDataCursor.getCount() : 0;
371f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
372f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
373f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public List<Suggestion> getSuggestions() {
374f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        ArrayList<Suggestion> list = Lists.newArrayList();
375f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mDataCursor != null) {
376f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Suggestion suggestion = null;
377f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            long currentContactId = -1;
378f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mDataCursor.moveToPosition(-1);
379f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            while (mDataCursor.moveToNext()) {
380f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                long contactId = mDataCursor.getLong(DataQuery.CONTACT_ID);
381f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (contactId != currentContactId) {
382f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    suggestion = new Suggestion();
383f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    suggestion.contactId = contactId;
384f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    suggestion.name = mDataCursor.getString(DataQuery.DISPLAY_NAME);
385c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    suggestion.lookupKey = mDataCursor.getString(DataQuery.LOOKUP_KEY);
386c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    suggestion.rawContacts = Lists.newArrayList();
387f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    list.add(suggestion);
388f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    currentContactId = contactId;
389f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
390f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
391c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                long rawContactId = mDataCursor.getLong(DataQuery.RAW_CONTACT_ID);
392c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                if (!containsRawContact(suggestion, rawContactId)) {
393c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    RawContact rawContact = new RawContact();
394c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    rawContact.rawContactId = rawContactId;
395c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    rawContact.accountName = mDataCursor.getString(DataQuery.ACCOUNT_NAME);
396c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    rawContact.accountType = mDataCursor.getString(DataQuery.ACCOUNT_TYPE);
3972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    rawContact.dataSet = mDataCursor.getString(DataQuery.DATA_SET);
398c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    suggestion.rawContacts.add(rawContact);
399f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
400f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
401f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                String mimetype = mDataCursor.getString(DataQuery.MIMETYPE);
402f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
403f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    String data = mDataCursor.getString(DataQuery.DATA1);
404f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
405f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (!TextUtils.isEmpty(data)
406f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            && (superprimary != 0 || suggestion.phoneNumber == null)) {
407f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.phoneNumber = data;
408f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
409f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
410f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    String data = mDataCursor.getString(DataQuery.DATA1);
411f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
412f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (!TextUtils.isEmpty(data)
413f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            && (superprimary != 0 || suggestion.emailAddress == null)) {
414f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.emailAddress = data;
415f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
416f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
417f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    String data = mDataCursor.getString(DataQuery.DATA1);
418f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (!TextUtils.isEmpty(data)) {
419f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.nickname = data;
420f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
421f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                } else if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
422f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    long dataId = mDataCursor.getLong(DataQuery.ID);
423f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    long photoId = mDataCursor.getLong(DataQuery.PHOTO_ID);
424f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (dataId == photoId && !mDataCursor.isNull(DataQuery.PHOTO)) {
425f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.photo = mDataCursor.getBlob(DataQuery.PHOTO);
426f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
427f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
428f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
429f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
430f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return list;
431f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
432c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov
433c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov    public boolean containsRawContact(Suggestion suggestion, long rawContactId) {
434c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        if (suggestion.rawContacts != null) {
435c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            int count = suggestion.rawContacts.size();
436c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            for (int i = 0; i < count; i++) {
437c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                if (suggestion.rawContacts.get(i).rawContactId == rawContactId) {
438c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    return true;
439c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                }
440c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            }
441c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        }
442c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        return false;
443c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov    }
444f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov}
445