Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 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 | */ |
Gary Mai | 69c182a | 2016-12-05 13:07:03 -0800 | [diff] [blame] | 16 | package com.android.contacts.list; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 17 | |
| 18 | import android.content.Context; |
| 19 | import android.content.CursorLoader; |
| 20 | import android.database.Cursor; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 21 | import android.database.MergeCursor; |
Sean Midford | c2deb41 | 2016-11-22 13:56:24 -0800 | [diff] [blame] | 22 | import android.database.sqlite.SQLiteException; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 23 | import android.os.Bundle; |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 24 | import android.provider.ContactsContract.Contacts; |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 25 | import android.util.Log; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 26 | |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 27 | import com.android.contacts.Experiments; |
| 28 | import com.android.contactsbind.ObjectFactory; |
| 29 | import com.android.contactsbind.experiments.Flags; |
| 30 | import com.android.contactsbind.search.AutocompleteHelper; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 31 | import com.google.common.collect.Lists; |
| 32 | |
| 33 | import java.util.List; |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 34 | import java.util.concurrent.CountDownLatch; |
| 35 | import java.util.concurrent.TimeUnit; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 36 | |
| 37 | /** |
Wenyi Wang | be88bed | 2016-05-13 12:04:14 -0700 | [diff] [blame] | 38 | * A loader for use in the default contact list, which will also query for favorite contacts |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 39 | * if configured to do so. |
| 40 | */ |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 41 | public class FavoritesAndContactsLoader extends CursorLoader implements |
| 42 | AutocompleteHelper.Listener { |
Walter Jang | fddbb83 | 2016-08-16 13:12:27 -0700 | [diff] [blame] | 43 | |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 44 | private boolean mLoadFavorites; |
| 45 | |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 46 | private String[] mProjection; |
Walter Jang | 1f82861 | 2016-02-09 16:15:37 -0800 | [diff] [blame] | 47 | |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 48 | private String mAutocompleteQuery; |
| 49 | private CountDownLatch mAutocompleteLatch = new CountDownLatch(1); |
| 50 | private Cursor mAutocompleteCursor; |
| 51 | private int mAutocompleteTimeout; |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 52 | |
Wenyi Wang | be88bed | 2016-05-13 12:04:14 -0700 | [diff] [blame] | 53 | public FavoritesAndContactsLoader(Context context) { |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 54 | super(context); |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 55 | mAutocompleteTimeout = Flags.getInstance().getInteger( |
| 56 | Experiments.SEARCH_YENTA_TIMEOUT_MILLIS); |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 57 | } |
| 58 | |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 59 | /** Whether to load favorites and merge results in before any other results. */ |
| 60 | public void setLoadFavorites(boolean flag) { |
| 61 | mLoadFavorites = flag; |
| 62 | } |
| 63 | |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 64 | public void setAutocompleteQuery(String autocompleteQuery) { |
| 65 | mAutocompleteQuery = autocompleteQuery; |
| 66 | } |
| 67 | |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 68 | public void setProjection(String[] projection) { |
| 69 | super.setProjection(projection); |
| 70 | mProjection = projection; |
| 71 | } |
| 72 | |
| 73 | @Override |
| 74 | public Cursor loadInBackground() { |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 75 | List<Cursor> cursors = Lists.newArrayList(); |
Wenyi Wang | f412a79 | 2016-04-13 11:52:29 -0700 | [diff] [blame] | 76 | if (mLoadFavorites) { |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 77 | cursors.add(loadFavoritesContacts()); |
| 78 | } |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 79 | |
| 80 | if (mAutocompleteQuery != null) { |
| 81 | final AutocompleteHelper autocompleteHelper = |
| 82 | ObjectFactory.getAutocompleteHelper(getContext()); |
| 83 | if (autocompleteHelper != null) { |
| 84 | autocompleteHelper.setListener(this); |
| 85 | autocompleteHelper.setProjection(mProjection); |
| 86 | autocompleteHelper.setQuery(mAutocompleteQuery); |
| 87 | try { |
| 88 | if (!mAutocompleteLatch.await(mAutocompleteTimeout, TimeUnit.MILLISECONDS)) { |
| 89 | logw("Timeout expired before receiving autocompletions"); |
| 90 | } |
| 91 | } catch (InterruptedException e) { |
| 92 | logw("Interrupted while waiting for autocompletions"); |
| 93 | } |
| 94 | if (mAutocompleteCursor != null) { |
| 95 | cursors.add(mAutocompleteCursor); |
| 96 | // TODO: exclude these results from the main loader results, see b/30742359 |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | // TODO: if the autocomplete experiment in on, only show those results even if they're empty |
| 102 | final Cursor contactsCursor = mAutocompleteQuery == null ? loadContacts() : null; |
| 103 | if (mAutocompleteQuery == null) { |
| 104 | cursors.add(contactsCursor); |
| 105 | } |
| 106 | // Guard against passing an empty array to the MergeCursor constructor |
| 107 | if (cursors.isEmpty()) cursors.add(null); |
| 108 | |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 109 | return new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) { |
| 110 | @Override |
| 111 | public Bundle getExtras() { |
| 112 | // Need to get the extras from the contacts cursor. |
Jay Shrauner | 49dbee1 | 2014-01-30 14:02:18 -0800 | [diff] [blame] | 113 | return contactsCursor == null ? new Bundle() : contactsCursor.getExtras(); |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 114 | } |
| 115 | }; |
| 116 | } |
| 117 | |
Walter Jang | fddbb83 | 2016-08-16 13:12:27 -0700 | [diff] [blame] | 118 | private Cursor loadContacts() { |
| 119 | // ContactsCursor.loadInBackground() can return null; MergeCursor |
| 120 | // correctly handles null cursors. |
| 121 | try { |
| 122 | return super.loadInBackground(); |
Sean Midford | c2deb41 | 2016-11-22 13:56:24 -0800 | [diff] [blame] | 123 | |
| 124 | } catch (NullPointerException | SQLiteException | SecurityException e) { |
| 125 | // Ignore NPEs, SQLiteExceptions and SecurityExceptions thrown by providers |
Walter Jang | fddbb83 | 2016-08-16 13:12:27 -0700 | [diff] [blame] | 126 | } |
| 127 | return null; |
Walter Jang | 5456440 | 2016-01-18 11:56:19 -0800 | [diff] [blame] | 128 | } |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 129 | |
| 130 | private Cursor loadFavoritesContacts() { |
yaolu | e81000b | 2016-10-03 17:07:34 -0700 | [diff] [blame] | 131 | final StringBuilder selection = new StringBuilder(); |
| 132 | selection.append(Contacts.STARRED + "=?"); |
| 133 | final ContactListFilter filter = |
| 134 | ContactListFilterController.getInstance(getContext()).getFilter(); |
| 135 | if (filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) { |
| 136 | selection.append(" AND ").append(Contacts.IN_VISIBLE_GROUP + "=1"); |
| 137 | } |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 138 | return getContext().getContentResolver().query( |
yaolu | e81000b | 2016-10-03 17:07:34 -0700 | [diff] [blame] | 139 | Contacts.CONTENT_URI, mProjection, selection.toString(), new String[]{"1"}, |
Wenyi Wang | 21fd2aa | 2016-06-05 15:52:07 -0700 | [diff] [blame] | 140 | getSortOrder()); |
Wenyi Wang | 25774d2 | 2016-04-08 11:15:11 -0700 | [diff] [blame] | 141 | } |
Walter Jang | f61f0ee | 2016-11-29 18:40:17 +0000 | [diff] [blame] | 142 | |
| 143 | @Override |
| 144 | public void onAutocompletesAvailable(Cursor cursor) { |
| 145 | if (cursor != null && cursor.getCount() > 0) { |
| 146 | mAutocompleteCursor = cursor; |
| 147 | mAutocompleteLatch.countDown(); |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | private static void logw(String message) { |
| 152 | if (Log.isLoggable(AutocompleteHelper.TAG, Log.WARN)) { |
| 153 | Log.w(AutocompleteHelper.TAG, message); |
| 154 | } |
| 155 | } |
Chiao Cheng | 89437e8 | 2012-11-01 13:41:51 -0700 | [diff] [blame] | 156 | } |