1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.util;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.Manifest;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.PackageManager;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.CommonDataKinds.Email;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.CommonDataKinds.Phone;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.Contacts;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.Directory;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.DisplayNameSources;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.PhoneLookup;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.Profile;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.ex.chips.RecipientEntry;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.CursorQueryData;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.FrequentContactsCursorQueryData;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsSmsUtils;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.contact.AddContactsConfirmationDialog;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.annotations.VisibleForTesting;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Utility class including logic to list, filter, and lookup phone and emails in CP2.
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd@VisibleForTesting
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class ContactUtil {
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Index of different columns in phone or email queries. All queries below should confirm to
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * this column content and ordering so that caller can use the uniformed way to process
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * returned cursors.
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_CONTACT_ID              = 0;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_DISPLAY_NAME            = 1;
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_PHOTO_URI               = 2;
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_PHONE_EMAIL             = 3;
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_PHONE_EMAIL_TYPE        = 4;
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_PHONE_EMAIL_LABEL       = 5;
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // An optional lookup_id column used by PhoneLookupQuery that is needed when querying for
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // contact information.
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_LOOKUP_KEY              = 6;
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // An optional _id column to query results that need to be displayed in a list view.
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_DATA_ID                 = 7;
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // An optional sort_key column for displaying contact section labels.
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_SORT_KEY                = 8;
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Lookup key column index specific to frequent contacts query.
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_LOOKUP_KEY_FREQUENT     = 3;
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Constants for listing and filtering phones.
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class PhoneQuery {
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String SORT_KEY = Phone.SORT_KEY_PRIMARY;
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.CONTACT_ID,                   // 0
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.DISPLAY_NAME_PRIMARY,         // 1
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.PHOTO_THUMBNAIL_URI,          // 2
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.NUMBER,                       // 3
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.TYPE,                         // 4
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.LABEL,                        // 5
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.LOOKUP_KEY,                   // 6
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone._ID,                          // 7
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneQuery.SORT_KEY,                // 8
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Constants for looking up phone numbers.
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class PhoneLookupQuery {
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // The _ID field points to the contact id of the content
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup._ID,                          // 0
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup.DISPLAY_NAME,                 // 1
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup.PHOTO_THUMBNAIL_URI,          // 2
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup.NUMBER,                       // 3
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup.TYPE,                         // 4
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup.LABEL,                        // 5
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PhoneLookup.LOOKUP_KEY,                   // 6
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // The data id is not included as part of the projection since it's not part of
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // PhoneLookup. This is okay because the _id field serves as both the data id and
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // contact id. Also we never show the results directly in a list view so we are not
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // concerned about duplicated _id's (namely, the same contact has two same phone
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // numbers)
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class FrequentContactQuery {
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Contacts._ID,                       // 0
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Contacts.DISPLAY_NAME,              // 1
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Contacts.PHOTO_URI,                 // 2
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Phone.LOOKUP_KEY,                   // 3
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Constants for listing and filtering emails.
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class EmailQuery {
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String SORT_KEY = Email.SORT_KEY_PRIMARY;
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.CONTACT_ID,                   // 0
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.DISPLAY_NAME_PRIMARY,         // 1
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.PHOTO_THUMBNAIL_URI,          // 2
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.ADDRESS,                      // 3
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.TYPE,                         // 4
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.LABEL,                        // 5
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email.LOOKUP_KEY,                   // 6
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Email._ID,                          // 7
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            EmailQuery.SORT_KEY,                // 8
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_SELF_QUERY_LOOKUP_KEY = 3;
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Constants for querying self from CP2.
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class SelfQuery {
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Profile._ID,                        // 0
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Profile.DISPLAY_NAME_PRIMARY,       // 1
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Profile.PHOTO_THUMBNAIL_URI,        // 2
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Profile.LOOKUP_KEY                  // 3
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Phone number, type, label and data_id is not provided in this projection since
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Profile CONTENT_URI doesn't include this information. Also, we don't need it
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // we just need the name and avatar url.
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class StructuredNameQuery {
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            StructuredName.DISPLAY_NAME,
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            StructuredName.GIVEN_NAME,
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            StructuredName.FAMILY_NAME,
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            StructuredName.PREFIX,
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            StructuredName.MIDDLE_NAME,
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            StructuredName.SUFFIX
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_STRUCTURED_NAME_DISPLAY_NAME = 0;
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_STRUCTURED_NAME_GIVEN_NAME = 1;
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_STRUCTURED_NAME_FAMILY_NAME = 2;
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_STRUCTURED_NAME_PREFIX = 3;
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_STRUCTURED_NAME_MIDDLE_NAME = 4;
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int INDEX_STRUCTURED_NAME_SUFFIX = 5;
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final long INVALID_CONTACT_ID = -1;
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This class is static. No need to create an instance.
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ContactUtil() {
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Shows a contact card or add to contacts dialog for the given contact info
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param view The view whose click triggered this to show
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param contactId The id of the contact in the android contacts DB
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param contactLookupKey The lookup key from contacts DB
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param avatarUri Uri to the avatar image if available
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param normalizedDestination The normalized phone number or email
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void showOrAddContact(final View view, final long contactId,
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String contactLookupKey, final Uri avatarUri,
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String normalizedDestination) {
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (contactId > ParticipantData.PARTICIPANT_CONTACT_ID_NOT_RESOLVED
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                && !TextUtils.isEmpty(contactLookupKey)) {
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Uri lookupUri =
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ContactsContract.Contacts.getLookupUri(contactId, contactLookupKey);
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ContactsContract.QuickContact.showQuickContact(view.getContext(), view, lookupUri,
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ContactsContract.QuickContact.MODE_LARGE, null);
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else if (!TextUtils.isEmpty(normalizedDestination) && !TextUtils.equals(
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                normalizedDestination, ParticipantData.getUnknownSenderDestination())) {
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final AddContactsConfirmationDialog dialog = new AddContactsConfirmationDialog(
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    view.getContext(), avatarUri, normalizedDestination);
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            dialog.show();
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData getSelf(final Context context) {
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new CursorQueryData(context, Profile.CONTENT_URI, SelfQuery.PROJECTION, null, null,
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                null);
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get a list of phones sorted by contact name. One contact may have multiple phones.
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * In that case, each phone will be returned as a separate record in the result cursor.
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData getPhones(final Context context) {
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // The AOSP Contacts provider allows adding a ContactsContract.REMOVE_DUPLICATE_ENTRIES
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // query parameter that removes duplicate (raw) numbers. Unfortunately, we can't use that
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // because it causes the some phones' contacts provider to return incorrect sections.
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = Phone.CONTENT_URI.buildUpon().appendQueryParameter(
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true")
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .build();
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new CursorQueryData(context, uri, PhoneQuery.PROJECTION, null, null,
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PhoneQuery.SORT_KEY);
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Lookup a destination (phone, email). Supplied destination should be a relatively complete
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * one for this to succeed. PhoneLookup / EmailLookup URI will apply some smartness to do a
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * loose match to see whether there is a contact that matches this destination.
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData lookupDestination(final Context context,
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String destination) {
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (MmsSmsUtils.isEmailAddress(destination)) {
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ContactUtil.lookupEmail(context, destination);
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ContactUtil.lookupPhone(context, destination);
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns whether the search text indicates an email based search or a phone number based one.
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean shouldFilterForEmail(final String searchText) {
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return searchText != null && searchText.contains("@");
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get a list of destinations (phone, email) matching the partial destination.
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData filterDestination(final Context context,
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String destination) {
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (shouldFilterForEmail(destination)) {
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ContactUtil.filterEmails(context, destination);
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ContactUtil.filterPhones(context, destination);
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
277b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak     * Get a list of destinations (phone, email) matching the partial destination in work profile.
278b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak     */
279b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    public static CursorQueryData filterDestinationEnterprise(final Context context,
280b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            final String destination) {
281b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        if (shouldFilterForEmail(destination)) {
282b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            return ContactUtil.filterEmailsEnterprise(context, destination);
283b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        } else {
284b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            return ContactUtil.filterPhonesEnterprise(context, destination);
285b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        }
286b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    }
287b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak
288b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    /**
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get a list of phones matching a search criteria. The search may be on contact name or
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * phone number. In case search is on contact name, all matching contact's phone number
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * will be returned.
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * NOTE: This is visible for testing only, clients should only call filterDestination() since
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * we support email addresses as well.
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData filterPhones(final Context context, final String query) {
297b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return filterPhonesInternal(context, Phone.CONTENT_FILTER_URI, query, Directory.DEFAULT);
298b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    }
299b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak
300b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    /**
301b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak     * Similar to {@link #filterPhones(Context, String)}, but search in work profile instead.
302b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak     */
303b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    public static CursorQueryData filterPhonesEnterprise(final Context context,
304b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            final String query) {
305b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return filterPhonesInternal(context, Phone.ENTERPRISE_CONTENT_FILTER_URI, query,
306b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                Directory.ENTERPRISE_DEFAULT);
307b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    }
308b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak
309b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    private static CursorQueryData filterPhonesInternal(final Context context,
310b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            final Uri phoneFilterBaseUri, final String query, final long directoryId) {
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
314b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        Uri phoneFilterUri = buildDirectorySearchUri(phoneFilterBaseUri, query, directoryId);
315b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return new CursorQueryData(context,
316b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                phoneFilterUri,
317b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                PhoneQuery.PROJECTION, null, null,
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PhoneQuery.SORT_KEY);
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Lookup a phone based on a phone number. Supplied phone should be a relatively complete
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * phone number for this to succeed. PhoneLookup URI will apply some smartness to do a
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * loose match to see whether there is a contact that matches this phone.
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * NOTE: This is visible for testing only, clients should only call lookupDestination() since
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * we support email addresses as well.
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData lookupPhone(final Context context, final String phone) {
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = getPhoneLookupUri().buildUpon()
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .appendPath(phone).build();
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new CursorQueryData(context, uri, PhoneLookupQuery.PROJECTION, null, null, null);
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get frequently contacted people. This queries for Contacts.CONTENT_STREQUENT_URI, which
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * includes both starred or frequently contacted people.
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData getFrequentContacts(final Context context) {
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new FrequentContactsCursorQueryData(context, FrequentContactQuery.PROJECTION,
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                null, null, null);
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get a list of emails matching a search criteria. In Bugle, since email is not a common
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * usage scenario, we should only do email search after user typed in a query indicating
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * an intention to search by email (for example, "joe@").
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * NOTE: This is visible for testing only, clients should only call filterDestination() since
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * we support email addresses as well.
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData filterEmails(final Context context, final String query) {
361b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return filterEmailsInternal(context, Email.CONTENT_FILTER_URI, query, Directory.DEFAULT);
362b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    }
363b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak
364b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    /**
365b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak     * Similar to {@link #filterEmails(Context, String)}, but search in work profile instead.
366b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak     */
367b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    public static CursorQueryData filterEmailsEnterprise(final Context context,
368b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            final String query) {
369b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return filterEmailsInternal(context, Email.ENTERPRISE_CONTENT_FILTER_URI, query,
370b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                Directory.ENTERPRISE_DEFAULT);
371b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    }
372b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak
373b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    private static CursorQueryData filterEmailsInternal(final Context context,
374b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            final Uri filterEmailsBaseUri, final String query, final long directoryId) {
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
378b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        final Uri filterEmailsUri = buildDirectorySearchUri(filterEmailsBaseUri, query,
379b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                directoryId);
380b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return new CursorQueryData(context,
381b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                filterEmailsUri,
382b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                PhoneQuery.PROJECTION, null, null,
383b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                PhoneQuery.SORT_KEY);
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Lookup emails based a complete email address. Since there is no special logic needed for
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * email lookup, this simply calls filterEmails.
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * NOTE: This is visible for testing only, clients should only call lookupDestination() since
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * we support email addresses as well.
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static CursorQueryData lookupEmail(final Context context, final String email) {
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = getEmailContentLookupUri().buildUpon()
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .appendPath(email).appendQueryParameter(
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        .build();
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new CursorQueryData(context, uri, EmailQuery.PROJECTION, null, null,
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                EmailQuery.SORT_KEY);
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Looks up the structured name for a contact.
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param primaryOnly If there are multiple raw contacts, set this flag to return only the
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * name used as the primary display name. Otherwise, this method returns all names.
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static CursorQueryData lookupStructuredName(final Context context, final long contactId,
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final boolean primaryOnly) {
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission()) {
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return CursorQueryData.getEmptyQueryData();
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // TODO: Handle enterprise contacts
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = ContactsContract.Contacts.CONTENT_URI.buildUpon()
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .appendPath(String.valueOf(contactId))
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .appendPath(ContactsContract.Contacts.Data.CONTENT_DIRECTORY).build();
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String selection = ContactsContract.Data.MIMETYPE + "=?";
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String[] selectionArgs = {
426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                StructuredName.CONTENT_ITEM_TYPE
427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (primaryOnly) {
429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selection += " AND " + Contacts.DISPLAY_NAME_PRIMARY + "="
430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + StructuredName.DISPLAY_NAME;
431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new CursorQueryData(context, uri,
434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                StructuredNameQuery.PROJECTION, selection, selectionArgs, null);
435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Looks up the first name for a contact. If there are multiple raw
439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * contacts, this returns the name that is associated with the contact's
440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * primary display name. The name is null when contact id does not exist
441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * (possibly because it is a corp contact) or it does not have a first name.
442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String lookupFirstName(final Context context, final long contactId) {
444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (isEnterpriseContactId(contactId)) {
445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String firstName = null;
448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor nameCursor = null;
449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            nameCursor = ContactUtil.lookupStructuredName(context, contactId, true)
451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    .performSynchronousQuery();
452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (nameCursor != null && nameCursor.moveToFirst()) {
453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                firstName = nameCursor.getString(ContactUtil.INDEX_STRUCTURED_NAME_GIVEN_NAME);
454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (nameCursor != null) {
457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                nameCursor.close();
458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return firstName;
461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Creates a RecipientEntry from the provided data fields (from the contacts cursor).
465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param firstLevel whether this item is the first entry of this contact in the list.
466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static RecipientEntry createRecipientEntry(final String displayName,
468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int displayNameSource, final String destination, final int destinationType,
469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String destinationLabel, final long contactId, final String lookupKey,
470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long dataId, final String photoThumbnailUri, final boolean firstLevel) {
471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (firstLevel) {
472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return RecipientEntry.constructTopLevelEntry(displayName, displayNameSource,
473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    destination, destinationType, destinationLabel, contactId, null, dataId,
474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    photoThumbnailUri, true, lookupKey);
475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return RecipientEntry.constructSecondLevelEntry(displayName, displayNameSource,
477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    destination, destinationType, destinationLabel, contactId, null, dataId,
478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    photoThumbnailUri, true, lookupKey);
479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
483d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Creates a RecipientEntry for PhoneQuery result. The result is then displayed in the
484d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * contact search drop down or as replacement chips in the chips edit box.
485d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
486d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static RecipientEntry createRecipientEntryForPhoneQuery(final Cursor cursor,
487d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final boolean isFirstLevel) {
488d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long contactId = cursor.getLong(ContactUtil.INDEX_CONTACT_ID);
489d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String displayName = cursor.getString(
490d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactUtil.INDEX_DISPLAY_NAME);
491d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String photoThumbnailUri = cursor.getString(
492d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactUtil.INDEX_PHOTO_URI);
493d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String destination = cursor.getString(
494d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactUtil.INDEX_PHONE_EMAIL);
495d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int destinationType = cursor.getInt(
496d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactUtil.INDEX_PHONE_EMAIL_TYPE);
497d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String destinationLabel = cursor.getString(
498d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactUtil.INDEX_PHONE_EMAIL_LABEL);
499d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String lookupKey = cursor.getString(
500d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContactUtil.INDEX_LOOKUP_KEY);
501d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
502d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // PhoneQuery uses the contact id as the data id ("_id").
503d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long dataId = contactId;
504d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
505d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return createRecipientEntry(displayName,
506d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                DisplayNameSources.STRUCTURED_NAME, destination, destinationType,
507d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                destinationLabel, contactId, lookupKey, dataId, photoThumbnailUri,
508d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                isFirstLevel);
509d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
510d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
511d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
512d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns if a given contact id is valid.
513d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
514d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isValidContactId(final long contactId) {
515d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return contactId >= 0;
516d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
517d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
518d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
519d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns if a given contact id belongs to managed profile.
520d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
521d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isEnterpriseContactId(final long contactId) {
522e2ccf8bff59da2b54fb037557ad93fc4c317c506Tony Mak        return OsUtil.isAtLeastL() && ContactsContract.Contacts.isEnterpriseContactId(contactId);
523d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
524d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
525d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
526d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns Email lookup uri that will query both primary and corp profile
527d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
528d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static Uri getEmailContentLookupUri() {
529e2ccf8bff59da2b54fb037557ad93fc4c317c506Tony Mak        if (OsUtil.isAtLeastM()) {
530e2ccf8bff59da2b54fb037557ad93fc4c317c506Tony Mak            return Email.ENTERPRISE_CONTENT_LOOKUP_URI;
531d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
532d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return Email.CONTENT_LOOKUP_URI;
533d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
534d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
535d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
536d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns PhoneLookup URI.
537d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
538d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static Uri getPhoneLookupUri() {
539e2ccf8bff59da2b54fb037557ad93fc4c317c506Tony Mak        if (OsUtil.isAtLeastM()) {
540d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI;
541d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
542d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return PhoneLookup.CONTENT_FILTER_URI;
543d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
544d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
545d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasReadContactsPermission() {
546d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return OsUtil.hasPermission(Manifest.permission.READ_CONTACTS);
547d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
548b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak
549b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    private static Uri buildDirectorySearchUri(final Uri uri, final String query,
550b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak            final long directoryId) {
551b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak        return uri.buildUpon()
552b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                .appendPath(query).appendQueryParameter(
553b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                        ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
554b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak                .build();
555b7fc988f231394077c08b5ede4d1a7310da57406Tony Mak    }
556d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
557