Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2010 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 | |
Dmitri Plotnikov | 18ffaa2 | 2010-12-03 14:28:00 -0800 | [diff] [blame] | 17 | package com.android.contacts.editor; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 18 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 19 | import android.content.ContentResolver; |
| 20 | import android.content.Context; |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 21 | import android.database.ContentObserver; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 22 | import android.database.Cursor; |
| 23 | import android.net.Uri; |
Wenyi Wang | 18fd938 | 2015-11-20 10:12:52 -0800 | [diff] [blame] | 24 | import android.os.Build; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 25 | import android.os.Handler; |
| 26 | import android.os.HandlerThread; |
| 27 | import android.os.Message; |
| 28 | import android.os.Process; |
| 29 | import android.provider.ContactsContract.CommonDataKinds.Email; |
| 30 | import android.provider.ContactsContract.CommonDataKinds.Nickname; |
| 31 | import android.provider.ContactsContract.CommonDataKinds.Phone; |
Gary Mai | 6a87ee9 | 2016-11-18 14:24:51 -0800 | [diff] [blame] | 32 | import android.provider.ContactsContract.CommonDataKinds.Photo; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 33 | import android.provider.ContactsContract.CommonDataKinds.StructuredName; |
| 34 | import android.provider.ContactsContract.Contacts; |
| 35 | import android.provider.ContactsContract.Contacts.AggregationSuggestions; |
| 36 | import android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder; |
| 37 | import android.provider.ContactsContract.Data; |
Dmitri Plotnikov | c0130cc | 2010-10-18 19:14:54 -0700 | [diff] [blame] | 38 | import android.provider.ContactsContract.RawContacts; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 39 | import android.text.TextUtils; |
| 40 | |
Chiao Cheng | 738ff86 | 2012-11-30 12:06:03 -0800 | [diff] [blame] | 41 | import com.android.contacts.common.model.ValuesDelta; |
Gary Mai | 220d10c | 2016-09-23 13:56:39 -0700 | [diff] [blame] | 42 | import com.android.contacts.common.model.account.AccountWithDataSet; |
Wenyi Wang | aac0e66 | 2015-12-18 17:17:33 -0800 | [diff] [blame] | 43 | import com.android.contacts.compat.AggregationSuggestionsCompat; |
Gary Mai | 6a87ee9 | 2016-11-18 14:24:51 -0800 | [diff] [blame] | 44 | |
John Shao | 0a7d717 | 2016-11-11 09:55:58 -0800 | [diff] [blame] | 45 | import com.google.common.base.MoreObjects; |
Chiao Cheng | e0b2f1e | 2012-06-12 13:07:56 -0700 | [diff] [blame] | 46 | import com.google.common.collect.Lists; |
| 47 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 48 | import java.util.ArrayList; |
| 49 | import java.util.Arrays; |
| 50 | import java.util.List; |
| 51 | |
| 52 | /** |
| 53 | * Runs asynchronous queries to obtain aggregation suggestions in the as-you-type mode. |
| 54 | */ |
| 55 | public class AggregationSuggestionEngine extends HandlerThread { |
| 56 | public static final String TAG = "AggregationSuggestionEngine"; |
| 57 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 58 | public interface Listener { |
| 59 | void onAggregationSuggestionChange(); |
| 60 | } |
| 61 | |
| 62 | public static final class Suggestion { |
| 63 | public long contactId; |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 64 | public String contactLookupKey; |
| 65 | public long rawContactId; |
Gary Mai | 6a87ee9 | 2016-11-18 14:24:51 -0800 | [diff] [blame] | 66 | public long photoId = -1; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 67 | public String name; |
| 68 | public String phoneNumber; |
| 69 | public String emailAddress; |
| 70 | public String nickname; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 71 | |
| 72 | @Override |
| 73 | public String toString() { |
John Shao | 0a7d717 | 2016-11-11 09:55:58 -0800 | [diff] [blame] | 74 | return MoreObjects.toStringHelper(Suggestion.class) |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 75 | .add("contactId", contactId) |
| 76 | .add("contactLookupKey", contactLookupKey) |
| 77 | .add("rawContactId", rawContactId) |
Gary Mai | 04926c0 | 2016-11-15 17:01:56 -0800 | [diff] [blame] | 78 | .add("photoId", photoId) |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 79 | .add("name", name) |
| 80 | .add("phoneNumber", phoneNumber) |
| 81 | .add("emailAddress", emailAddress) |
| 82 | .add("nickname", nickname) |
| 83 | .toString(); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 87 | private final class SuggestionContentObserver extends ContentObserver { |
| 88 | private SuggestionContentObserver(Handler handler) { |
| 89 | super(handler); |
| 90 | } |
| 91 | |
| 92 | @Override |
| 93 | public void onChange(boolean selfChange) { |
| 94 | scheduleSuggestionLookup(); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | private static final int MESSAGE_RESET = 0; |
| 99 | private static final int MESSAGE_NAME_CHANGE = 1; |
| 100 | private static final int MESSAGE_DATA_CURSOR = 2; |
| 101 | |
| 102 | private static final long SUGGESTION_LOOKUP_DELAY_MILLIS = 300; |
| 103 | |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 104 | private static final int SUGGESTIONS_LIMIT = 3; |
| 105 | |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 106 | private final Context mContext; |
| 107 | |
| 108 | private long[] mSuggestedContactIds = new long[0]; |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 109 | private Handler mMainHandler; |
| 110 | private Handler mHandler; |
| 111 | private long mContactId; |
Gary Mai | 220d10c | 2016-09-23 13:56:39 -0700 | [diff] [blame] | 112 | private AccountWithDataSet mAccountFilter; |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 113 | private Listener mListener; |
| 114 | private Cursor mDataCursor; |
| 115 | private ContentObserver mContentObserver; |
| 116 | private Uri mSuggestionsUri; |
| 117 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 118 | public AggregationSuggestionEngine(Context context) { |
| 119 | super("AggregationSuggestions", Process.THREAD_PRIORITY_BACKGROUND); |
Makoto Onuki | 2828c48 | 2012-04-27 15:01:44 -0700 | [diff] [blame] | 120 | mContext = context.getApplicationContext(); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 121 | mMainHandler = new Handler() { |
| 122 | @Override |
| 123 | public void handleMessage(Message msg) { |
| 124 | AggregationSuggestionEngine.this.deliverNotification((Cursor) msg.obj); |
| 125 | } |
| 126 | }; |
| 127 | } |
| 128 | |
| 129 | protected Handler getHandler() { |
| 130 | if (mHandler == null) { |
| 131 | mHandler = new Handler(getLooper()) { |
| 132 | @Override |
| 133 | public void handleMessage(Message msg) { |
| 134 | AggregationSuggestionEngine.this.handleMessage(msg); |
| 135 | } |
| 136 | }; |
| 137 | } |
| 138 | return mHandler; |
| 139 | } |
| 140 | |
| 141 | public void setContactId(long contactId) { |
Dmitri Plotnikov | 916cf26 | 2010-10-19 17:30:01 -0700 | [diff] [blame] | 142 | if (contactId != mContactId) { |
| 143 | mContactId = contactId; |
| 144 | reset(); |
| 145 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 146 | } |
| 147 | |
Gary Mai | 220d10c | 2016-09-23 13:56:39 -0700 | [diff] [blame] | 148 | public void setAccountFilter(AccountWithDataSet account) { |
| 149 | mAccountFilter = account; |
| 150 | } |
| 151 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 152 | public void setListener(Listener listener) { |
| 153 | mListener = listener; |
| 154 | } |
| 155 | |
| 156 | @Override |
| 157 | public boolean quit() { |
| 158 | if (mDataCursor != null) { |
| 159 | mDataCursor.close(); |
| 160 | } |
| 161 | mDataCursor = null; |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 162 | if (mContentObserver != null) { |
| 163 | mContext.getContentResolver().unregisterContentObserver(mContentObserver); |
| 164 | mContentObserver = null; |
| 165 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 166 | return super.quit(); |
| 167 | } |
| 168 | |
Dmitri Plotnikov | 9302ba7 | 2010-10-14 18:08:40 -0700 | [diff] [blame] | 169 | public void reset() { |
| 170 | Handler handler = getHandler(); |
| 171 | handler.removeMessages(MESSAGE_NAME_CHANGE); |
| 172 | handler.sendEmptyMessage(MESSAGE_RESET); |
| 173 | } |
| 174 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 175 | public void onNameChange(ValuesDelta values) { |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 176 | mSuggestionsUri = buildAggregationSuggestionUri(values); |
| 177 | if (mSuggestionsUri != null) { |
| 178 | if (mContentObserver == null) { |
| 179 | mContentObserver = new SuggestionContentObserver(getHandler()); |
| 180 | mContext.getContentResolver().registerContentObserver( |
| 181 | Contacts.CONTENT_URI, true, mContentObserver); |
| 182 | } |
| 183 | } else if (mContentObserver != null) { |
| 184 | mContext.getContentResolver().unregisterContentObserver(mContentObserver); |
| 185 | mContentObserver = null; |
| 186 | } |
| 187 | scheduleSuggestionLookup(); |
| 188 | } |
| 189 | |
| 190 | protected void scheduleSuggestionLookup() { |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 191 | Handler handler = getHandler(); |
| 192 | handler.removeMessages(MESSAGE_NAME_CHANGE); |
| 193 | |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 194 | if (mSuggestionsUri == null) { |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 195 | return; |
| 196 | } |
| 197 | |
Dmitri Plotnikov | d52121b | 2010-12-10 12:17:25 -0800 | [diff] [blame] | 198 | Message msg = handler.obtainMessage(MESSAGE_NAME_CHANGE, mSuggestionsUri); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 199 | handler.sendMessageDelayed(msg, SUGGESTION_LOOKUP_DELAY_MILLIS); |
| 200 | } |
| 201 | |
| 202 | private Uri buildAggregationSuggestionUri(ValuesDelta values) { |
| 203 | StringBuilder nameSb = new StringBuilder(); |
| 204 | appendValue(nameSb, values, StructuredName.PREFIX); |
| 205 | appendValue(nameSb, values, StructuredName.GIVEN_NAME); |
| 206 | appendValue(nameSb, values, StructuredName.MIDDLE_NAME); |
| 207 | appendValue(nameSb, values, StructuredName.FAMILY_NAME); |
| 208 | appendValue(nameSb, values, StructuredName.SUFFIX); |
| 209 | |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 210 | StringBuilder phoneticNameSb = new StringBuilder(); |
| 211 | appendValue(phoneticNameSb, values, StructuredName.PHONETIC_FAMILY_NAME); |
| 212 | appendValue(phoneticNameSb, values, StructuredName.PHONETIC_MIDDLE_NAME); |
| 213 | appendValue(phoneticNameSb, values, StructuredName.PHONETIC_GIVEN_NAME); |
| 214 | |
| 215 | if (nameSb.length() == 0 && phoneticNameSb.length() == 0) { |
| 216 | return null; |
| 217 | } |
| 218 | |
Wenyi Wang | 18fd938 | 2015-11-20 10:12:52 -0800 | [diff] [blame] | 219 | // AggregationSuggestions.Builder() became visible in API level 23, so use it if applicable. |
| 220 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
| 221 | final Builder uriBuilder = new AggregationSuggestions.Builder() |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 222 | .setLimit(SUGGESTIONS_LIMIT) |
Wenyi Wang | 18fd938 | 2015-11-20 10:12:52 -0800 | [diff] [blame] | 223 | .setContactId(mContactId); |
| 224 | if (nameSb.length() != 0) { |
| 225 | uriBuilder.addNameParameter(nameSb.toString()); |
| 226 | } |
| 227 | if (phoneticNameSb.length() != 0) { |
| 228 | uriBuilder.addNameParameter(phoneticNameSb.toString()); |
| 229 | } |
| 230 | return uriBuilder.build(); |
| 231 | } |
| 232 | |
| 233 | // For previous SDKs, use the backup plan. |
| 234 | final AggregationSuggestionsCompat.Builder uriBuilder = |
| 235 | new AggregationSuggestionsCompat.Builder() |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 236 | .setLimit(SUGGESTIONS_LIMIT) |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 237 | .setContactId(mContactId); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 238 | if (nameSb.length() != 0) { |
Wenyi Wang | 18fd938 | 2015-11-20 10:12:52 -0800 | [diff] [blame] | 239 | uriBuilder.addNameParameter(nameSb.toString()); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 240 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 241 | if (phoneticNameSb.length() != 0) { |
Wenyi Wang | 18fd938 | 2015-11-20 10:12:52 -0800 | [diff] [blame] | 242 | uriBuilder.addNameParameter(phoneticNameSb.toString()); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 243 | } |
Wenyi Wang | 18fd938 | 2015-11-20 10:12:52 -0800 | [diff] [blame] | 244 | return uriBuilder.build(); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | private void appendValue(StringBuilder sb, ValuesDelta values, String column) { |
| 248 | String value = values.getAsString(column); |
| 249 | if (!TextUtils.isEmpty(value)) { |
| 250 | if (sb.length() > 0) { |
| 251 | sb.append(' '); |
| 252 | } |
| 253 | sb.append(value); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | protected void handleMessage(Message msg) { |
Dmitri Plotnikov | 9302ba7 | 2010-10-14 18:08:40 -0700 | [diff] [blame] | 258 | switch (msg.what) { |
| 259 | case MESSAGE_RESET: |
| 260 | mSuggestedContactIds = new long[0]; |
| 261 | break; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 262 | case MESSAGE_NAME_CHANGE: |
| 263 | loadAggregationSuggestions((Uri) msg.obj); |
| 264 | break; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | private static final class DataQuery { |
| 269 | |
| 270 | public static final String SELECTION_PREFIX = |
| 271 | Data.MIMETYPE + " IN ('" |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 272 | + Phone.CONTENT_ITEM_TYPE + "','" |
| 273 | + Email.CONTENT_ITEM_TYPE + "','" |
| 274 | + StructuredName.CONTENT_ITEM_TYPE + "','" |
Gary Mai | 6a87ee9 | 2016-11-18 14:24:51 -0800 | [diff] [blame] | 275 | + Nickname.CONTENT_ITEM_TYPE + "','" |
| 276 | + Photo.CONTENT_ITEM_TYPE + "')" |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 277 | + " AND " + Data.CONTACT_ID + " IN ("; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 278 | |
| 279 | public static final String[] COLUMNS = { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 280 | Data.CONTACT_ID, |
| 281 | Data.LOOKUP_KEY, |
| 282 | Data.RAW_CONTACT_ID, |
| 283 | Data.MIMETYPE, |
| 284 | Data.DATA1, |
| 285 | Data.IS_SUPER_PRIMARY, |
| 286 | RawContacts.ACCOUNT_TYPE, |
| 287 | RawContacts.ACCOUNT_NAME, |
Gary Mai | 04926c0 | 2016-11-15 17:01:56 -0800 | [diff] [blame] | 288 | RawContacts.DATA_SET, |
Gary Mai | 6a87ee9 | 2016-11-18 14:24:51 -0800 | [diff] [blame] | 289 | Contacts.Photo._ID |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 290 | }; |
| 291 | |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 292 | public static final int CONTACT_ID = 0; |
| 293 | public static final int LOOKUP_KEY = 1; |
| 294 | public static final int RAW_CONTACT_ID = 2; |
| 295 | public static final int MIMETYPE = 3; |
| 296 | public static final int DATA1 = 4; |
| 297 | public static final int IS_SUPERPRIMARY = 5; |
| 298 | public static final int ACCOUNT_TYPE = 6; |
| 299 | public static final int ACCOUNT_NAME = 7; |
| 300 | public static final int DATA_SET = 8; |
Gary Mai | 04926c0 | 2016-11-15 17:01:56 -0800 | [diff] [blame] | 301 | public static final int PHOTO_ID = 9; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | private void loadAggregationSuggestions(Uri uri) { |
| 305 | ContentResolver contentResolver = mContext.getContentResolver(); |
| 306 | Cursor cursor = contentResolver.query(uri, new String[]{Contacts._ID}, null, null, null); |
Jay Shrauner | 13c42f4 | 2014-01-27 17:06:27 -0800 | [diff] [blame] | 307 | if (cursor == null) { |
| 308 | return; |
| 309 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 310 | try { |
| 311 | // If a new request is pending, chuck the result of the previous request |
| 312 | if (getHandler().hasMessages(MESSAGE_NAME_CHANGE)) { |
| 313 | return; |
| 314 | } |
| 315 | |
| 316 | boolean changed = updateSuggestedContactIds(cursor); |
| 317 | if (!changed) { |
| 318 | return; |
| 319 | } |
| 320 | |
| 321 | StringBuilder sb = new StringBuilder(DataQuery.SELECTION_PREFIX); |
| 322 | int count = mSuggestedContactIds.length; |
| 323 | for (int i = 0; i < count; i++) { |
| 324 | if (i > 0) { |
| 325 | sb.append(','); |
| 326 | } |
| 327 | sb.append(mSuggestedContactIds[i]); |
| 328 | } |
| 329 | sb.append(')'); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 330 | |
| 331 | Cursor dataCursor = contentResolver.query(Data.CONTENT_URI, |
| 332 | DataQuery.COLUMNS, sb.toString(), null, Data.CONTACT_ID); |
Jay Shrauner | 13c42f4 | 2014-01-27 17:06:27 -0800 | [diff] [blame] | 333 | if (dataCursor != null) { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 334 | mMainHandler.sendMessage( |
| 335 | mMainHandler.obtainMessage(MESSAGE_DATA_CURSOR, dataCursor)); |
Jay Shrauner | 13c42f4 | 2014-01-27 17:06:27 -0800 | [diff] [blame] | 336 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 337 | } finally { |
| 338 | cursor.close(); |
| 339 | } |
| 340 | } |
| 341 | |
Jay Shrauner | 5a57e57 | 2014-05-29 13:41:24 -0700 | [diff] [blame] | 342 | private boolean updateSuggestedContactIds(final Cursor cursor) { |
| 343 | final int count = cursor.getCount(); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 344 | boolean changed = count != mSuggestedContactIds.length; |
Jay Shrauner | 5a57e57 | 2014-05-29 13:41:24 -0700 | [diff] [blame] | 345 | final ArrayList<Long> newIds = new ArrayList<Long>(count); |
| 346 | while (cursor.moveToNext()) { |
| 347 | final long contactId = cursor.getLong(0); |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 348 | if (!changed && Arrays.binarySearch(mSuggestedContactIds, contactId) < 0) { |
Jay Shrauner | 5a57e57 | 2014-05-29 13:41:24 -0700 | [diff] [blame] | 349 | changed = true; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 350 | } |
Jay Shrauner | 5a57e57 | 2014-05-29 13:41:24 -0700 | [diff] [blame] | 351 | newIds.add(contactId); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 352 | } |
| 353 | |
| 354 | if (changed) { |
Jay Shrauner | 5a57e57 | 2014-05-29 13:41:24 -0700 | [diff] [blame] | 355 | mSuggestedContactIds = new long[newIds.size()]; |
| 356 | int i = 0; |
| 357 | for (final Long newId : newIds) { |
| 358 | mSuggestedContactIds[i++] = newId; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 359 | } |
| 360 | Arrays.sort(mSuggestedContactIds); |
| 361 | } |
| 362 | |
| 363 | return changed; |
| 364 | } |
| 365 | |
| 366 | protected void deliverNotification(Cursor dataCursor) { |
| 367 | if (mDataCursor != null) { |
| 368 | mDataCursor.close(); |
| 369 | } |
| 370 | mDataCursor = dataCursor; |
| 371 | if (mListener != null) { |
| 372 | mListener.onAggregationSuggestionChange(); |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | public int getSuggestedContactCount() { |
Dmitri Plotnikov | 9302ba7 | 2010-10-14 18:08:40 -0700 | [diff] [blame] | 377 | return mDataCursor != null ? mDataCursor.getCount() : 0; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 378 | } |
| 379 | |
| 380 | public List<Suggestion> getSuggestions() { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 381 | final ArrayList<Suggestion> list = Lists.newArrayList(); |
Tingting Wang | e5e6a2a | 2015-10-22 16:53:31 -0700 | [diff] [blame] | 382 | |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 383 | if (mDataCursor != null && mAccountFilter != null) { |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 384 | Suggestion suggestion = null; |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 385 | long currentRawContactId = -1; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 386 | mDataCursor.moveToPosition(-1); |
| 387 | while (mDataCursor.moveToNext()) { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 388 | final long rawContactId = mDataCursor.getLong(DataQuery.RAW_CONTACT_ID); |
| 389 | if (rawContactId != currentRawContactId) { |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 390 | suggestion = new Suggestion(); |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 391 | suggestion.rawContactId = rawContactId; |
| 392 | suggestion.contactId = mDataCursor.getLong(DataQuery.CONTACT_ID); |
| 393 | suggestion.contactLookupKey = mDataCursor.getString(DataQuery.LOOKUP_KEY); |
| 394 | final String accountName = mDataCursor.getString(DataQuery.ACCOUNT_NAME); |
| 395 | final String accountType = mDataCursor.getString(DataQuery.ACCOUNT_TYPE); |
| 396 | final String dataSet = mDataCursor.getString(DataQuery.DATA_SET); |
Gary Mai | 220d10c | 2016-09-23 13:56:39 -0700 | [diff] [blame] | 397 | final AccountWithDataSet account = new AccountWithDataSet( |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 398 | accountName, accountType, dataSet); |
| 399 | if (mAccountFilter.equals(account)) { |
Gary Mai | 220d10c | 2016-09-23 13:56:39 -0700 | [diff] [blame] | 400 | list.add(suggestion); |
| 401 | } |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 402 | currentRawContactId = rawContactId; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 403 | } |
| 404 | |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 405 | final String mimetype = mDataCursor.getString(DataQuery.MIMETYPE); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 406 | if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 407 | final String data = mDataCursor.getString(DataQuery.DATA1); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 408 | int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY); |
| 409 | if (!TextUtils.isEmpty(data) |
| 410 | && (superprimary != 0 || suggestion.phoneNumber == null)) { |
| 411 | suggestion.phoneNumber = data; |
| 412 | } |
| 413 | } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 414 | final String data = mDataCursor.getString(DataQuery.DATA1); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 415 | int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY); |
| 416 | if (!TextUtils.isEmpty(data) |
| 417 | && (superprimary != 0 || suggestion.emailAddress == null)) { |
| 418 | suggestion.emailAddress = data; |
| 419 | } |
| 420 | } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) { |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 421 | final String data = mDataCursor.getString(DataQuery.DATA1); |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 422 | if (!TextUtils.isEmpty(data)) { |
| 423 | suggestion.nickname = data; |
| 424 | } |
Gary Mai | 678108e | 2016-10-26 14:34:33 -0700 | [diff] [blame] | 425 | } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) { |
| 426 | // DATA1 stores the display name for the raw contact. |
| 427 | final String data = mDataCursor.getString(DataQuery.DATA1); |
| 428 | if (!TextUtils.isEmpty(data) && suggestion.name == null) { |
| 429 | suggestion.name = data; |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 430 | } |
Gary Mai | 6a87ee9 | 2016-11-18 14:24:51 -0800 | [diff] [blame] | 431 | } else if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) { |
| 432 | final Long id = mDataCursor.getLong(DataQuery.PHOTO_ID); |
| 433 | if (suggestion.photoId == -1) { |
| 434 | suggestion.photoId = id; |
| 435 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 436 | } |
| 437 | } |
| 438 | } |
| 439 | return list; |
| 440 | } |
Dmitri Plotnikov | f491ae9 | 2010-08-16 12:18:53 -0700 | [diff] [blame] | 441 | } |