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
40738ff8623dc77dd91a1b9023861e924ba5e4c27eChiao Chengimport com.android.contacts.common.model.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
221532df59787a7b0b41aa3177dc1e2a073f2b8c3c3Brian Attwell        Builder builder = new AggregationSuggestions.Builder()
222f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                .setLimit(MAX_SUGGESTION_COUNT)
223f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                .setContactId(mContactId);
224f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
225f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (nameSb.length() != 0) {
226bd2db2d4a756d9ca02a945f6dcf720f6bf983e0aBrian Attwell            builder.addNameParameter(nameSb.toString());
227f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
228f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
229f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (phoneticNameSb.length() != 0) {
230bd2db2d4a756d9ca02a945f6dcf720f6bf983e0aBrian Attwell            builder.addNameParameter(phoneticNameSb.toString());
231f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
232f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
233f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return builder.build();
234f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
235f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
236f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private void appendValue(StringBuilder sb, ValuesDelta values, String column) {
237f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        String value = values.getAsString(column);
238f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (!TextUtils.isEmpty(value)) {
239f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (sb.length() > 0) {
240f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                sb.append(' ');
241f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
242f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            sb.append(value);
243f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
244f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
245f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
246f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected void handleMessage(Message msg) {
2479302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        switch (msg.what) {
2489302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            case MESSAGE_RESET:
2499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                mSuggestedContactIds = new long[0];
2509302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                break;
251f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            case MESSAGE_NAME_CHANGE:
252f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                loadAggregationSuggestions((Uri) msg.obj);
253f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                break;
254f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
255f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
256f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
257f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private static final class DataQuery {
258f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
259f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final String SELECTION_PREFIX =
260f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                Data.MIMETYPE + " IN ('"
261f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Phone.CONTENT_ITEM_TYPE + "','"
262f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Email.CONTENT_ITEM_TYPE + "','"
263f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + StructuredName.CONTENT_ITEM_TYPE + "','"
264f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Nickname.CONTENT_ITEM_TYPE + "','"
265f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    + Photo.CONTENT_ITEM_TYPE + "')"
266f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                + " AND " + Data.CONTACT_ID + " IN (";
267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
268f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final String[] COLUMNS = {
269f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data._ID,
270f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.CONTACT_ID,
271f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.LOOKUP_KEY,
272f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.PHOTO_ID,
273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.DISPLAY_NAME,
274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.RAW_CONTACT_ID,
275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.MIMETYPE,
276f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.DATA1,
277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Data.IS_SUPER_PRIMARY,
278f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Photo.PHOTO,
279c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
280c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
2812b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            RawContacts.DATA_SET
282f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        };
283f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
284f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int ID = 0;
285f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int CONTACT_ID = 1;
286f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int LOOKUP_KEY = 2;
287f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int PHOTO_ID = 3;
288f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int DISPLAY_NAME = 4;
289f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 5;
290f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int MIMETYPE = 6;
291f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int DATA1 = 7;
292f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int IS_SUPERPRIMARY = 8;
293f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        public static final int PHOTO = 9;
294c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public static final int ACCOUNT_TYPE = 10;
295c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        public static final int ACCOUNT_NAME = 11;
2962b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        public static final int DATA_SET = 12;
297f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
298f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
299f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private void loadAggregationSuggestions(Uri uri) {
300f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        ContentResolver contentResolver = mContext.getContentResolver();
301f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Cursor cursor = contentResolver.query(uri, new String[]{Contacts._ID}, null, null, null);
30213c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner        if (cursor == null) {
30313c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner            return;
30413c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner        }
305f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        try {
306f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            // If a new request is pending, chuck the result of the previous request
307f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (getHandler().hasMessages(MESSAGE_NAME_CHANGE)) {
308f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                return;
309f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
310f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
311f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            boolean changed = updateSuggestedContactIds(cursor);
312f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (!changed) {
313f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                return;
314f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
315f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
316f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            StringBuilder sb = new StringBuilder(DataQuery.SELECTION_PREFIX);
317f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            int count = mSuggestedContactIds.length;
318f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            for (int i = 0; i < count; i++) {
319f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (i > 0) {
320f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    sb.append(',');
321f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
322f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                sb.append(mSuggestedContactIds[i]);
323f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
324f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            sb.append(')');
325f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            sb.toString();
326f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
327f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Cursor dataCursor = contentResolver.query(Data.CONTENT_URI,
328f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    DataQuery.COLUMNS, sb.toString(), null, Data.CONTACT_ID);
32913c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner            if (dataCursor != null) {
33013c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                mMainHandler.sendMessage(mMainHandler.obtainMessage(MESSAGE_DATA_CURSOR, dataCursor));
33113c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner            }
332f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        } finally {
333f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            cursor.close();
334f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
335f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
336f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
3375a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner    private boolean updateSuggestedContactIds(final Cursor cursor) {
3385a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner        final int count = cursor.getCount();
339f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        boolean changed = count != mSuggestedContactIds.length;
3405a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner        final ArrayList<Long> newIds = new ArrayList<Long>(count);
3415a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner        while (cursor.moveToNext()) {
3425a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner            final long contactId = cursor.getLong(0);
3435a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner            if (!changed &&
3445a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner                    Arrays.binarySearch(mSuggestedContactIds, contactId) < 0) {
3455a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner                changed = true;
346f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
3475a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner            newIds.add(contactId);
348f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
349f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
350f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (changed) {
3515a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner            mSuggestedContactIds = new long[newIds.size()];
3525a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner            int i = 0;
3535a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner            for (final Long newId : newIds) {
3545a57e57c122edefbeea40a35102d53598aebfc1cJay Shrauner                mSuggestedContactIds[i++] = newId;
355f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
356f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Arrays.sort(mSuggestedContactIds);
357f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
358f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
359f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return changed;
360f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
361f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
362f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected void deliverNotification(Cursor dataCursor) {
363f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mDataCursor != null) {
364f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mDataCursor.close();
365f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
366f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mDataCursor = dataCursor;
367f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mListener != null) {
368f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mListener.onAggregationSuggestionChange();
369f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
370f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
371f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
372f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public int getSuggestedContactCount() {
3739302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return mDataCursor != null ? mDataCursor.getCount() : 0;
374f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
375f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
376f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public List<Suggestion> getSuggestions() {
377f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        ArrayList<Suggestion> list = Lists.newArrayList();
378f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mDataCursor != null) {
379f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Suggestion suggestion = null;
380f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            long currentContactId = -1;
381f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mDataCursor.moveToPosition(-1);
382f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            while (mDataCursor.moveToNext()) {
383f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                long contactId = mDataCursor.getLong(DataQuery.CONTACT_ID);
384f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (contactId != currentContactId) {
385f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    suggestion = new Suggestion();
386f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    suggestion.contactId = contactId;
387f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    suggestion.name = mDataCursor.getString(DataQuery.DISPLAY_NAME);
388c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    suggestion.lookupKey = mDataCursor.getString(DataQuery.LOOKUP_KEY);
389c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    suggestion.rawContacts = Lists.newArrayList();
390f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    list.add(suggestion);
391f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    currentContactId = contactId;
392f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
393f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
394c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                long rawContactId = mDataCursor.getLong(DataQuery.RAW_CONTACT_ID);
395c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                if (!containsRawContact(suggestion, rawContactId)) {
396c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    RawContact rawContact = new RawContact();
397c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    rawContact.rawContactId = rawContactId;
398c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    rawContact.accountName = mDataCursor.getString(DataQuery.ACCOUNT_NAME);
399c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    rawContact.accountType = mDataCursor.getString(DataQuery.ACCOUNT_TYPE);
4002b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    rawContact.dataSet = mDataCursor.getString(DataQuery.DATA_SET);
401c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    suggestion.rawContacts.add(rawContact);
402f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
403f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
404f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                String mimetype = mDataCursor.getString(DataQuery.MIMETYPE);
405f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
406f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    String data = mDataCursor.getString(DataQuery.DATA1);
407f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
408f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (!TextUtils.isEmpty(data)
409f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            && (superprimary != 0 || suggestion.phoneNumber == null)) {
410f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.phoneNumber = data;
411f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
412f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
413f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    String data = mDataCursor.getString(DataQuery.DATA1);
414f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
415f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (!TextUtils.isEmpty(data)
416f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            && (superprimary != 0 || suggestion.emailAddress == null)) {
417f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.emailAddress = data;
418f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
419f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
420f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    String data = mDataCursor.getString(DataQuery.DATA1);
421f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (!TextUtils.isEmpty(data)) {
422f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.nickname = data;
423f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
424f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                } else if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
425f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    long dataId = mDataCursor.getLong(DataQuery.ID);
426f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    long photoId = mDataCursor.getLong(DataQuery.PHOTO_ID);
427f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    if (dataId == photoId && !mDataCursor.isNull(DataQuery.PHOTO)) {
428f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                        suggestion.photo = mDataCursor.getBlob(DataQuery.PHOTO);
429f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
430f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
431f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
432f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
433f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return list;
434f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
435c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov
436c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov    public boolean containsRawContact(Suggestion suggestion, long rawContactId) {
437c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        if (suggestion.rawContacts != null) {
438c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            int count = suggestion.rawContacts.size();
439c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            for (int i = 0; i < count; i++) {
440c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                if (suggestion.rawContacts.get(i).rawContactId == rawContactId) {
441c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                    return true;
442c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov                }
443c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            }
444c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        }
445c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov        return false;
446c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov    }
447f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov}
448