1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/*
2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2010 The Android Open Source Project
3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License.
6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at
7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software
11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and
14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License.
15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */
16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.contacts.common.list;
18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context;
203331545bd3fb769ae3f9246c0bd92fe35c6308absailimport android.content.CursorLoader;
21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.database.Cursor;
22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.net.Uri;
23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.net.Uri.Builder;
24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract;
25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract.CommonDataKinds.Callable;
26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract.CommonDataKinds.Phone;
27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract.Contacts;
29ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract.Directory;
3010ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanianimport android.support.annotation.VisibleForTesting;
31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextUtils;
32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.View;
33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.ViewGroup;
34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.ContactsUtils;
36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.R;
37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.compat.CallableCompat;
38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.compat.DirectoryCompat;
39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.compat.PhoneCompat;
40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor;
412f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanianimport com.android.contacts.common.lettertiles.LetterTileDrawable;
4210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.contacts.common.list.ContactListItemView.CallToAction;
43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.preference.ContactsPreferences;
44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.util.Constants;
4510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.common.LogUtil;
46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.compat.CompatUtils;
472f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanianimport com.android.dialer.dialercontact.DialerContact;
4810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.enrichedcall.EnrichedCallCapabilities;
4910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.enrichedcall.EnrichedCallComponent;
5010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.enrichedcall.EnrichedCallManager;
512f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanianimport com.android.dialer.lightbringer.LightbringerComponent;
5210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.location.GeoUtil;
53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.util.CallUtil;
54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.ArrayList;
55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.Arrays;
56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.List;
57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/**
59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * A cursor adapter for the {@link Phone#CONTENT_ITEM_TYPE} and {@link
60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * SipAddress#CONTENT_ITEM_TYPE}.
61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>By default this adapter just handles phone numbers. When {@link #setUseCallableUri(boolean)}
63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * is called with "true", this adapter starts handling SIP addresses too, by using {@link Callable}
64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * API instead of {@link Phone}.
65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */
66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class PhoneNumberListAdapter extends ContactEntryListAdapter {
67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();
69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE = "length(" + Phone.NUMBER + ") < 1000";
70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  // A list of extended directories to add to the directories from the database
71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final List<DirectoryPartition> mExtendedDirectories;
72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final CharSequence mUnknownNameText;
732f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  protected final boolean mIsImsVideoEnabled;
742f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
75ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  // Extended directories will have ID's that are higher than any of the id's from the database,
76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  // so that we can identify them and set them up properly. If no extended directories
77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  // exist, this will be Long.MAX_VALUE
78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private long mFirstExtendedDirectoryId = Long.MAX_VALUE;
79ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mUseCallableUri;
80ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private Listener mListener;
81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public PhoneNumberListAdapter(Context context) {
83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    super(context);
84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    setDefaultFilterHeaderText(R.string.list_filter_phones);
85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mUnknownNameText = context.getText(android.R.string.unknownName);
86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mExtendedDirectories =
88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        PhoneDirectoryExtenderAccessor.get(mContext).getExtendedDirectories(mContext);
89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    int videoCapabilities = CallUtil.getVideoCallingAvailability(context);
912f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    mIsImsVideoEnabled =
922f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        CallUtil.isVideoEnabled(context)
932f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian            && (videoCapabilities & CallUtil.VIDEO_CALLING_PRESENCE) != 0;
94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void configureLoader(CursorLoader loader, long directoryId) {
98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    String query = getQueryString();
99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (query == null) {
100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      query = "";
101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (isExtendedDirectory(directoryId)) {
103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final DirectoryPartition directory = getExtendedDirectoryFromId(directoryId);
104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final String contentUri = directory.getContentUri();
105ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (contentUri == null) {
106ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        throw new IllegalStateException("Extended directory must have a content URL: " + directory);
107ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Builder builder = Uri.parse(contentUri).buildUpon();
109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      builder.appendPath(query);
110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      builder.appendQueryParameter(
111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          ContactsContract.LIMIT_PARAM_KEY, String.valueOf(getDirectoryResultLimit(directory)));
112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      loader.setUri(builder.build());
113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final boolean isRemoteDirectoryQuery = DirectoryCompat.isRemoteDirectoryId(directoryId);
116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Builder builder;
117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (isSearchMode()) {
118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final Uri baseUri;
119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (isRemoteDirectoryQuery) {
120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          baseUri = PhoneCompat.getContentFilterUri();
121ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        } else if (mUseCallableUri) {
122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          baseUri = CallableCompat.getContentFilterUri();
123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        } else {
124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          baseUri = PhoneCompat.getContentFilterUri();
125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        builder = baseUri.buildUpon();
127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        builder.appendPath(query); // Builder will encode the query
128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        builder.appendQueryParameter(
129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId));
130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (isRemoteDirectoryQuery) {
131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          builder.appendQueryParameter(
132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              ContactsContract.LIMIT_PARAM_KEY,
133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        builder =
138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            baseUri
139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                .buildUpon()
140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                .appendQueryParameter(
141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                    ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (isSectionHeaderDisplayEnabled()) {
143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          builder.appendQueryParameter(Phone.EXTRA_ADDRESS_BOOK_INDEX, "true");
144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        applyFilter(loader, builder, directoryId, getFilter());
146ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
147ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
148ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Ignore invalid phone numbers that are too long. These can potentially cause freezes
149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // in the UI and there is no reason to display them.
150ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final String prevSelection = loader.getSelection();
151ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final String newSelection;
152ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (!TextUtils.isEmpty(prevSelection)) {
153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        newSelection = prevSelection + " AND " + IGNORE_NUMBER_TOO_LONG_CLAUSE;
154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        newSelection = IGNORE_NUMBER_TOO_LONG_CLAUSE;
156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      loader.setSelection(newSelection);
158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Remove duplicates when it is possible.
160ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
161ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      loader.setUri(builder.build());
162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // TODO a projection that includes the search snippet
164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected boolean isExtendedDirectory(long directoryId) {
179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return directoryId >= mFirstExtendedDirectoryId;
180ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
182ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private DirectoryPartition getExtendedDirectoryFromId(long directoryId) {
183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final int directoryIndex = (int) (directoryId - mFirstExtendedDirectoryId);
184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mExtendedDirectories.get(directoryIndex);
185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Configure {@code loader} and {@code uriBuilder} according to {@code directoryId} and {@code
189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * filter}.
190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void applyFilter(
192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      CursorLoader loader, Uri.Builder uriBuilder, long directoryId, ContactListFilter filter) {
193ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (filter == null || directoryId != Directory.DEFAULT) {
194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final StringBuilder selection = new StringBuilder();
198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final List<String> selectionArgs = new ArrayList<String>();
199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    switch (filter.filterType) {
201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case ContactListFilter.FILTER_TYPE_CUSTOM:
202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        {
203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
204ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          break;
206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case ContactListFilter.FILTER_TYPE_ACCOUNT:
208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        {
209ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          filter.addAccountQueryParameterToUrl(uriBuilder);
210ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          break;
211ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
212ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS:
213ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case ContactListFilter.FILTER_TYPE_DEFAULT:
214ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        break; // No selection needed.
215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        break; // This adapter is always "phone only", so no selection needed either.
217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      default:
21810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        LogUtil.w(
219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            TAG,
220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            "Unsupported filter type came "
221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                + "(type: "
222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                + filter.filterType
223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                + ", toString: "
224ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                + filter
225ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                + ")"
226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                + " showing all contacts.");
227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        // No selection.
228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        break;
229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    loader.setSelection(selection.toString());
231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public String getPhoneNumber(int position) {
235ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final Cursor item = (Cursor) getItem(position);
236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return item != null ? item.getString(PhoneQuery.PHONE_NUMBER) : null;
237ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Retrieves the lookup key for the given cursor position.
241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
242ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @param position The cursor position.
243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @return The lookup key.
244ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public String getLookupKey(int position) {
246ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final Cursor item = (Cursor) getItem(position);
247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return item != null ? item.getString(PhoneQuery.LOOKUP_KEY) : null;
248ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
2502f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  public DialerContact getDialerContact(int position) {
25110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    Cursor cursor = (Cursor) getItem(position);
25210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (cursor == null) {
2532f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      LogUtil.e("PhoneNumberListAdapter.getDialerContact", "cursor was null.");
25410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      return null;
25510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
25610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
25710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    String displayName = cursor.getString(PhoneQuery.DISPLAY_NAME);
25810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    String number = cursor.getString(PhoneQuery.PHONE_NUMBER);
25910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    String photoUri = cursor.getString(PhoneQuery.PHOTO_URI);
26010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    Uri contactUri =
26110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        Contacts.getLookupUri(
26210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian            cursor.getLong(PhoneQuery.CONTACT_ID), cursor.getString(PhoneQuery.LOOKUP_KEY));
26310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
2642f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    DialerContact.Builder contact = DialerContact.newBuilder();
26510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    contact
26610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .setNumber(number)
26710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .setPhotoId(cursor.getLong(PhoneQuery.PHOTO_ID))
2682f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .setContactType(LetterTileDrawable.TYPE_DEFAULT)
26910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .setNameOrNumber(displayName)
27010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .setNumberLabel(
27110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian            Phone.getTypeLabel(
27210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                    mContext.getResources(),
27310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                    cursor.getInt(PhoneQuery.PHONE_TYPE),
27410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                    cursor.getString(PhoneQuery.PHONE_LABEL))
27510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                .toString());
27610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
27710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (photoUri != null) {
27810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      contact.setPhotoUri(photoUri);
27910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
28010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
28110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (contactUri != null) {
28210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      contact.setContactUri(contactUri.toString());
28310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
28410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
28510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (!TextUtils.isEmpty(displayName)) {
28610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      contact.setDisplayNumber(number);
28710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
28810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
28910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return contact.build();
29010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
29110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
292ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
293ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected ContactListItemView newView(
294ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
295ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    ContactListItemView view = super.newView(context, partition, cursor, position, parent);
296ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.setUnknownNameText(mUnknownNameText);
297ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.setQuickContactEnabled(isQuickContactEnabled());
298ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return view;
299ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
300ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
301ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void setHighlight(ContactListItemView view, Cursor cursor) {
302ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
303ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
304ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
305ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
306ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void bindView(View itemView, int partition, Cursor cursor, int position) {
307ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    super.bindView(itemView, partition, cursor, position);
308ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    ContactListItemView view = (ContactListItemView) itemView;
309ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
310ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    setHighlight(view, cursor);
311ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
312ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Look at elements before and after this position, checking if contact IDs are same.
313ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // If they have one same contact ID, it means they can be grouped.
314ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    //
315ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // In one group, only the first entry will show its photo and its name, and the other
316ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // entries in the group show just their data (e.g. phone number, email address).
317ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    cursor.moveToPosition(position);
318ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    boolean isFirstEntry = true;
319ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final long currentContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
320ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (cursor.moveToPrevious() && !cursor.isBeforeFirst()) {
321ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final long previousContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
322ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (currentContactId == previousContactId) {
323ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        isFirstEntry = false;
324ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
325ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
326ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    cursor.moveToPosition(position);
327ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
328ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    bindViewId(view, cursor, PhoneQuery.PHONE_ID);
329ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
330ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    bindSectionHeaderAndDivider(view, position);
331ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (isFirstEntry) {
332ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      bindName(view, cursor);
333ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (isQuickContactEnabled()) {
334ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        bindQuickContact(
335ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            view,
336ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            partition,
337ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            cursor,
338ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            PhoneQuery.PHOTO_ID,
339ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            PhoneQuery.PHOTO_URI,
340ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            PhoneQuery.CONTACT_ID,
341ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            PhoneQuery.LOOKUP_KEY,
342ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            PhoneQuery.DISPLAY_NAME);
343ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
344ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (getDisplayPhotos()) {
345ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          bindPhoto(view, partition, cursor);
346ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
347ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
348ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
349ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      unbindName(view);
350ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
351ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      view.removePhotoView(true, false);
352ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
353ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
354ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
3552f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    // All sections have headers, so scroll position is off by 1.
3562f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    position += getPositionForPartition(partition) + 1;
357ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
358ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    bindPhoneNumber(view, cursor, directory.isDisplayNumber(), position);
359ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
360ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
36110ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian  @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
36210ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian  public void bindPhoneNumber(
363ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      ContactListItemView view, Cursor cursor, boolean displayNumber, int position) {
364ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    CharSequence label = null;
365ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (displayNumber && !cursor.isNull(PhoneQuery.PHONE_TYPE)) {
366ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
367ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final String customLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
368ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
369ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // TODO cache
37010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      label = Phone.getTypeLabel(mContext.getResources(), type, customLabel);
371ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
372ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.setLabel(label);
373ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final String text;
37410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    String number = cursor.getString(PhoneQuery.PHONE_NUMBER);
375ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (displayNumber) {
37610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      text = number;
377ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
378ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Display phone label. If that's null, display geocoded location for the number
379ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final String phoneLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
380ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (phoneLabel != null) {
381ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        text = phoneLabel;
382ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
383ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final String phoneNumber = cursor.getString(PhoneQuery.PHONE_NUMBER);
384ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        text = GeoUtil.getGeocodedLocationFor(mContext, phoneNumber);
385ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
386ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
387ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.setPhoneNumber(text);
388ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
38910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    @CallToAction int action = ContactListItemView.NONE;
39010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
391ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (CompatUtils.isVideoCompatible()) {
392ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Determine if carrier presence indicates the number supports video calling.
393ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      int carrierPresence = cursor.getInt(PhoneQuery.CARRIER_PRESENCE);
394ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      boolean isPresent = (carrierPresence & Phone.CARRIER_PRESENCE_VT_CAPABLE) != 0;
395ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
3962f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      boolean showViewIcon = mIsImsVideoEnabled && isPresent;
3972f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      if (showViewIcon) {
39810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        action = ContactListItemView.VIDEO;
39910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      }
40010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
40110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
40210ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian    if (action == ContactListItemView.NONE
40310ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian        && LightbringerComponent.get(mContext).getLightbringer().isReachable(mContext, number)) {
4042f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      action = ContactListItemView.LIGHTBRINGER;
4052f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    }
4062f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
4072f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    if (action == ContactListItemView.NONE) {
40810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      EnrichedCallManager manager = EnrichedCallComponent.get(mContext).getEnrichedCallManager();
40910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      EnrichedCallCapabilities capabilities = manager.getCapabilities(number);
41010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      if (capabilities != null && capabilities.supportsCallComposer()) {
41110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        action = ContactListItemView.CALL_AND_SHARE;
41210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      } else if (capabilities == null
41310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          && getQueryString() != null
41410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          && getQueryString().length() >= 3) {
41510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        manager.requestCapabilities(number);
41610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      }
417ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
41810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
41910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    view.setCallToAction(action, mListener, position);
420ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
421ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
422ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
423ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (isSectionHeaderDisplayEnabled()) {
424ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      Placement placement = getItemPlacementInSection(position);
425ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
426ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
427ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      view.setSectionHeader(null);
428ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
429ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
430ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
431ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void bindName(final ContactListItemView view, Cursor cursor) {
432ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.showDisplayName(cursor, PhoneQuery.DISPLAY_NAME);
433ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Note: we don't show phonetic names any more (see issue 5265330)
434ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
435ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
436ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void unbindName(final ContactListItemView view) {
437ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.hideDisplayName();
438ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
439ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
440ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
441ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void bindWorkProfileIcon(final ContactListItemView view, int partition) {
442ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
443ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final long directoryId = directory.getDirectoryId();
444ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final long userType = ContactsUtils.determineUserType(directoryId, null);
445ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Work directory must not be a extended directory. An extended directory is custom
446ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // directory in the app, but not a directory provided by framework. So it can't be
447ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // USER_TYPE_WORK.
448ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    view.setWorkProfileIconEnabled(
449ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        !isExtendedDirectory(directoryId) && userType == ContactsUtils.USER_TYPE_WORK);
450ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
451ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
452ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
453ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (!isPhotoSupported(partitionIndex)) {
454ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      view.removePhotoView();
455ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
456ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
457ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
458ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    long photoId = 0;
459ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
460ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
461ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
462ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
463ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (photoId != 0) {
464ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      getPhotoLoader()
465ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          .loadThumbnail(view.getPhotoView(), photoId, false, getCircularPhotos(), null);
466ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
467ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
468ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
469ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
470ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      DefaultImageRequest request = null;
471ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (photoUri == null) {
472ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final String displayName = cursor.getString(PhoneQuery.DISPLAY_NAME);
473ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final String lookupKey = cursor.getString(PhoneQuery.LOOKUP_KEY);
474ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        request = new DefaultImageRequest(displayName, lookupKey, getCircularPhotos());
475ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
476ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      getPhotoLoader()
477ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          .loadDirectoryPhoto(view.getPhotoView(), photoUri, false, getCircularPhotos(), request);
478ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
479ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
480ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
481ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void setUseCallableUri(boolean useCallableUri) {
482ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mUseCallableUri = useCallableUri;
483ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
484ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
485ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
486ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Override base implementation to inject extended directories between local & remote directories.
487ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * This is done in the following steps: 1. Call base implementation to add directories from the
488ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * cursor. 2. Iterate all base directories and establish the following information: a. The highest
489ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * directory id so that we can assign unused id's to the extended directories. b. The index of the
490ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * last non-remote directory. This is where we will insert extended directories. 3. Iterate the
491ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * extended directories and for each one, assign an ID and insert it in the proper location.
492ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
493ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
494ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void changeDirectories(Cursor cursor) {
495ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    super.changeDirectories(cursor);
496ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (getDirectorySearchMode() == DirectoryListLoader.SEARCH_MODE_NONE) {
497ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
498ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
499ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final int numExtendedDirectories = mExtendedDirectories.size();
500ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (getPartitionCount() == cursor.getCount() + numExtendedDirectories) {
501ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // already added all directories;
502ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
503ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
504ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    //
505ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mFirstExtendedDirectoryId = Long.MAX_VALUE;
506ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (numExtendedDirectories > 0) {
507ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // The Directory.LOCAL_INVISIBLE is not in the cursor but we can't reuse it's
508ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // "special" ID.
509ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      long maxId = Directory.LOCAL_INVISIBLE;
510ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      int insertIndex = 0;
511ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      for (int i = 0, n = getPartitionCount(); i < n; i++) {
512ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final DirectoryPartition partition = (DirectoryPartition) getPartition(i);
513ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final long id = partition.getDirectoryId();
514ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (id > maxId) {
515ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          maxId = id;
516ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
517ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (!DirectoryCompat.isRemoteDirectoryId(id)) {
518ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          // assuming remote directories come after local, we will end up with the index
519ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          // where we should insert extended directories. This also works if there are no
520ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          // remote directories at all.
521ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          insertIndex = i + 1;
522ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
523ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
524ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Extended directories ID's cannot collide with base directories
525ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mFirstExtendedDirectoryId = maxId + 1;
526ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      for (int i = 0; i < numExtendedDirectories; i++) {
527ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final long id = mFirstExtendedDirectoryId + i;
528ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final DirectoryPartition directory = mExtendedDirectories.get(i);
529ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (getPartitionByDirectoryId(id) == -1) {
530ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          addPartition(insertIndex, directory);
531ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          directory.setDirectoryId(id);
532ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
533ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
534ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
535ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
536ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
537ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
538ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  protected Uri getContactUri(
539ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      int partitionIndex, Cursor cursor, int contactIdColumn, int lookUpKeyColumn) {
540ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final DirectoryPartition directory = (DirectoryPartition) getPartition(partitionIndex);
541ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final long directoryId = directory.getDirectoryId();
542ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (!isExtendedDirectory(directoryId)) {
543ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return super.getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn);
544ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
545ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return Contacts.CONTENT_LOOKUP_URI
546ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        .buildUpon()
547ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        .appendPath(Constants.LOOKUP_URI_ENCODED)
548ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        .appendQueryParameter(Directory.DISPLAY_NAME, directory.getLabel())
549ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
550ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        .encodedFragment(cursor.getString(lookUpKeyColumn))
551ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        .build();
552ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
553ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
554ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public Listener getListener() {
555ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mListener;
556ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
557ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
558ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void setListener(Listener listener) {
559ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mListener = listener;
560ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
561ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
562ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public interface Listener {
563ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
564ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void onVideoCallIconClicked(int position);
56510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
5662f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    void onLightbringerIconClicked(int position);
5672f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
56810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    void onCallAndShareIconClicked(int position);
569ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
570ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
571ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public static class PhoneQuery {
572ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
573ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    /**
574ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * Optional key used as part of a JSON lookup key to specify an analytics category associated
575ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * with the row.
576ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     */
577ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String ANALYTICS_CATEGORY = "analytics_category";
578ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
579ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    /**
580ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * Optional key used as part of a JSON lookup key to specify an analytics action associated with
581ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * the row.
582ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     */
583ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String ANALYTICS_ACTION = "analytics_action";
584ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
585ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    /**
586ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * Optional key used as part of a JSON lookup key to specify an analytics value associated with
587ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * the row.
588ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     */
589ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String ANALYTICS_VALUE = "analytics_value";
590ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
591ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String[] PROJECTION_PRIMARY_INTERNAL =
592ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new String[] {
593ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone._ID, // 0
594ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.TYPE, // 1
595ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.LABEL, // 2
596ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.NUMBER, // 3
597ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.CONTACT_ID, // 4
598ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.LOOKUP_KEY, // 5
599ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.PHOTO_ID, // 6
600ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.DISPLAY_NAME_PRIMARY, // 7
601ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.PHOTO_THUMBNAIL_URI, // 8
602ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        };
603ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
604ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String[] PROJECTION_PRIMARY;
605ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String[] PROJECTION_ALTERNATIVE_INTERNAL =
606ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new String[] {
607ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone._ID, // 0
608ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.TYPE, // 1
609ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.LABEL, // 2
610ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.NUMBER, // 3
611ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.CONTACT_ID, // 4
612ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.LOOKUP_KEY, // 5
613ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.PHOTO_ID, // 6
614ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.DISPLAY_NAME_ALTERNATIVE, // 7
615ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Phone.PHOTO_THUMBNAIL_URI, // 8
616ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        };
617ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final String[] PROJECTION_ALTERNATIVE;
618ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int PHONE_ID = 0;
619ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int PHONE_TYPE = 1;
620ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int PHONE_LABEL = 2;
621ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int PHONE_NUMBER = 3;
622ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int CONTACT_ID = 4;
623ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int LOOKUP_KEY = 5;
624ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int PHOTO_ID = 6;
625ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int DISPLAY_NAME = 7;
626ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int PHOTO_URI = 8;
627ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public static final int CARRIER_PRESENCE = 9;
628ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
629ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    static {
630ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final List<String> projectionList =
631ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          new ArrayList<>(Arrays.asList(PROJECTION_PRIMARY_INTERNAL));
6322f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      projectionList.add(Phone.CARRIER_PRESENCE); // 9
633ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      PROJECTION_PRIMARY = projectionList.toArray(new String[projectionList.size()]);
634ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
635ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
636ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    static {
637ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final List<String> projectionList =
638ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          new ArrayList<>(Arrays.asList(PROJECTION_ALTERNATIVE_INTERNAL));
6392f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      projectionList.add(Phone.CARRIER_PRESENCE); // 9
640ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      PROJECTION_ALTERNATIVE = projectionList.toArray(new String[projectionList.size()]);
641ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
642ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
643ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian}
644