blob: 5868d29a674d4bcf2a111ace04ccfa24b62f58b0 [file] [log] [blame]
Chiao Cheng89437e82012-11-01 13:41:51 -07001/*
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 Mai69c182a2016-12-05 13:07:03 -080016package com.android.contacts.list;
Chiao Cheng89437e82012-11-01 13:41:51 -070017
18import android.content.Context;
19import android.content.CursorLoader;
20import android.database.Cursor;
Chiao Cheng89437e82012-11-01 13:41:51 -070021import android.database.MergeCursor;
Sean Midfordc2deb412016-11-22 13:56:24 -080022import android.database.sqlite.SQLiteException;
Chiao Cheng89437e82012-11-01 13:41:51 -070023import android.os.Bundle;
Wenyi Wang25774d22016-04-08 11:15:11 -070024import android.provider.ContactsContract.Contacts;
Walter Jangf61f0ee2016-11-29 18:40:17 +000025import android.util.Log;
Chiao Cheng89437e82012-11-01 13:41:51 -070026
Walter Jangf61f0ee2016-11-29 18:40:17 +000027import com.android.contacts.Experiments;
28import com.android.contactsbind.ObjectFactory;
29import com.android.contactsbind.experiments.Flags;
30import com.android.contactsbind.search.AutocompleteHelper;
Chiao Cheng89437e82012-11-01 13:41:51 -070031import com.google.common.collect.Lists;
32
33import java.util.List;
Walter Jangf61f0ee2016-11-29 18:40:17 +000034import java.util.concurrent.CountDownLatch;
35import java.util.concurrent.TimeUnit;
Chiao Cheng89437e82012-11-01 13:41:51 -070036
37/**
Wenyi Wangbe88bed2016-05-13 12:04:14 -070038 * A loader for use in the default contact list, which will also query for favorite contacts
Chiao Cheng89437e82012-11-01 13:41:51 -070039 * if configured to do so.
40 */
Walter Jangf61f0ee2016-11-29 18:40:17 +000041public class FavoritesAndContactsLoader extends CursorLoader implements
42 AutocompleteHelper.Listener {
Walter Jangfddbb832016-08-16 13:12:27 -070043
Wenyi Wang25774d22016-04-08 11:15:11 -070044 private boolean mLoadFavorites;
45
Chiao Cheng89437e82012-11-01 13:41:51 -070046 private String[] mProjection;
Walter Jang1f828612016-02-09 16:15:37 -080047
Walter Jangf61f0ee2016-11-29 18:40:17 +000048 private String mAutocompleteQuery;
49 private CountDownLatch mAutocompleteLatch = new CountDownLatch(1);
50 private Cursor mAutocompleteCursor;
51 private int mAutocompleteTimeout;
Chiao Cheng89437e82012-11-01 13:41:51 -070052
Wenyi Wangbe88bed2016-05-13 12:04:14 -070053 public FavoritesAndContactsLoader(Context context) {
Chiao Cheng89437e82012-11-01 13:41:51 -070054 super(context);
Walter Jangf61f0ee2016-11-29 18:40:17 +000055 mAutocompleteTimeout = Flags.getInstance().getInteger(
56 Experiments.SEARCH_YENTA_TIMEOUT_MILLIS);
Chiao Cheng89437e82012-11-01 13:41:51 -070057 }
58
Wenyi Wang25774d22016-04-08 11:15:11 -070059 /** Whether to load favorites and merge results in before any other results. */
60 public void setLoadFavorites(boolean flag) {
61 mLoadFavorites = flag;
62 }
63
Walter Jangf61f0ee2016-11-29 18:40:17 +000064 public void setAutocompleteQuery(String autocompleteQuery) {
65 mAutocompleteQuery = autocompleteQuery;
66 }
67
Chiao Cheng89437e82012-11-01 13:41:51 -070068 public void setProjection(String[] projection) {
69 super.setProjection(projection);
70 mProjection = projection;
71 }
72
73 @Override
74 public Cursor loadInBackground() {
Chiao Cheng89437e82012-11-01 13:41:51 -070075 List<Cursor> cursors = Lists.newArrayList();
Wenyi Wangf412a792016-04-13 11:52:29 -070076 if (mLoadFavorites) {
Wenyi Wang25774d22016-04-08 11:15:11 -070077 cursors.add(loadFavoritesContacts());
78 }
Walter Jangf61f0ee2016-11-29 18:40:17 +000079
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 Cheng89437e82012-11-01 13:41:51 -0700109 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 Shrauner49dbee12014-01-30 14:02:18 -0800113 return contactsCursor == null ? new Bundle() : contactsCursor.getExtras();
Chiao Cheng89437e82012-11-01 13:41:51 -0700114 }
115 };
116 }
117
Walter Jangfddbb832016-08-16 13:12:27 -0700118 private Cursor loadContacts() {
119 // ContactsCursor.loadInBackground() can return null; MergeCursor
120 // correctly handles null cursors.
121 try {
122 return super.loadInBackground();
Sean Midfordc2deb412016-11-22 13:56:24 -0800123
124 } catch (NullPointerException | SQLiteException | SecurityException e) {
125 // Ignore NPEs, SQLiteExceptions and SecurityExceptions thrown by providers
Walter Jangfddbb832016-08-16 13:12:27 -0700126 }
127 return null;
Walter Jang54564402016-01-18 11:56:19 -0800128 }
Wenyi Wang25774d22016-04-08 11:15:11 -0700129
130 private Cursor loadFavoritesContacts() {
yaolue81000b2016-10-03 17:07:34 -0700131 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 Wang25774d22016-04-08 11:15:11 -0700138 return getContext().getContentResolver().query(
yaolue81000b2016-10-03 17:07:34 -0700139 Contacts.CONTENT_URI, mProjection, selection.toString(), new String[]{"1"},
Wenyi Wang21fd2aa2016-06-05 15:52:07 -0700140 getSortOrder());
Wenyi Wang25774d22016-04-08 11:15:11 -0700141 }
Walter Jangf61f0ee2016-11-29 18:40:17 +0000142
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 Cheng89437e82012-11-01 13:41:51 -0700156}