11040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki/* 21040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * Copyright (C) 2015 The Android Open Source Project 31040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * 41040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 51040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * you may not use this file except in compliance with the License. 61040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * You may obtain a copy of the License at 71040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * 81040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 91040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * 101040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * Unless required by applicable law or agreed to in writing, software 111040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 121040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * See the License for the specific language governing permissions and 141040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * limitations under the License 151040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki */ 161040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukipackage android.provider; 171040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 181040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.app.admin.DevicePolicyManager; 191040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.content.ActivityNotFoundException; 201040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.content.ContentUris; 211040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.content.Context; 221040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.content.Intent; 231040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.content.UriMatcher; 241040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.net.Uri; 251040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.os.Process; 261040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.os.UserHandle; 271040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.text.TextUtils; 281040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport android.widget.Toast; 291040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 301040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukiimport java.util.List; 311040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 321040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki/** 331040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * Contacts related internal methods. 341040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * 351040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * @hide 361040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki */ 371040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onukipublic class ContactsInternal { 381040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki private ContactsInternal() { 391040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 401040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 411040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki /** URI matcher used to parse contact URIs. */ 421040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki private static final UriMatcher sContactsUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 431040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 441040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki private static final int CONTACTS_URI_LOOKUP_ID = 1000; 4597bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang private static final int CONTACTS_URI_LOOKUP = 1001; 461040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 471040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki static { 481040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki // Contacts URI matching table 491040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final UriMatcher matcher = sContactsUriMatcher; 5097bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_URI_LOOKUP); 511040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_URI_LOOKUP_ID); 521040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 531040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 541040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki /** 551040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * Called by {@link ContactsContract} to star Quick Contact, possibly on the managed profile. 561040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki */ 571040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki public static void startQuickContactWithErrorToast(Context context, Intent intent) { 581040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final Uri uri = intent.getData(); 591040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 601040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final int match = sContactsUriMatcher.match(uri); 611040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki switch (match) { 6297bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang case CONTACTS_URI_LOOKUP: 631040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki case CONTACTS_URI_LOOKUP_ID: { 641040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki if (maybeStartManagedQuickContact(context, intent)) { 651040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki return; // Request handled by DPM. Just return here. 661040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 671040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki break; 681040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 691040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 701040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki // Launch on the current profile. 711040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki startQuickContactWithErrorToastForUser(context, intent, Process.myUserHandle()); 721040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 731040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 741040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki public static void startQuickContactWithErrorToastForUser(Context context, Intent intent, 751040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki UserHandle user) { 761040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki try { 771040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki context.startActivityAsUser(intent, user); 781040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } catch (ActivityNotFoundException e) { 791040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, 801040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki Toast.LENGTH_SHORT).show(); 811040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 821040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 831040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 841040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki /** 851040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * If the URI in {@code intent} is of a corp contact, launch quick contact on the managed 861040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * profile. 871040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * 881040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki * @return the URI in {@code intent} is of a corp contact thus launched on the managed profile. 891040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki */ 901040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki private static boolean maybeStartManagedQuickContact(Context context, Intent originalIntent) { 911040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final Uri uri = originalIntent.getData(); 921040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 931040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki // Decompose into an ID and a lookup key. 941040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final List<String> pathSegments = uri.getPathSegments(); 9597bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang final boolean isContactIdIgnored = pathSegments.size() < 4; 9697bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang final long contactId = isContactIdIgnored 9797bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang ? ContactsContract.Contacts.ENTERPRISE_CONTACT_ID_BASE //contact id will be ignored 9897bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang : ContentUris.parseId(uri); 991040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final String lookupKey = pathSegments.get(2); 100494b95d30266335044a854845219b6e34cf43edbRicky Wai final String directoryIdStr = uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY); 101494b95d30266335044a854845219b6e34cf43edbRicky Wai final long directoryId = (directoryIdStr == null) 102494b95d30266335044a854845219b6e34cf43edbRicky Wai ? ContactsContract.Directory.ENTERPRISE_DIRECTORY_ID_BASE 103494b95d30266335044a854845219b6e34cf43edbRicky Wai : Long.parseLong(directoryIdStr); 1041040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 1051040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki // See if it has a corp lookupkey. 1061040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki if (TextUtils.isEmpty(lookupKey) 1071040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki || !lookupKey.startsWith( 1081040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX)) { 1091040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki return false; // It's not a corp lookup key. 1101040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 1111040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 112494b95d30266335044a854845219b6e34cf43edbRicky Wai if (!ContactsContract.Contacts.isEnterpriseContactId(contactId)) { 113494b95d30266335044a854845219b6e34cf43edbRicky Wai throw new IllegalArgumentException("Invalid enterprise contact id: " + contactId); 114494b95d30266335044a854845219b6e34cf43edbRicky Wai } 115494b95d30266335044a854845219b6e34cf43edbRicky Wai if (!ContactsContract.Directory.isEnterpriseDirectoryId(directoryId)) { 116494b95d30266335044a854845219b6e34cf43edbRicky Wai throw new IllegalArgumentException("Invalid enterprise directory id: " + directoryId); 117494b95d30266335044a854845219b6e34cf43edbRicky Wai } 118494b95d30266335044a854845219b6e34cf43edbRicky Wai 1191040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki // Launch Quick Contact on the managed profile, if the policy allows. 1201040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 1211040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final String actualLookupKey = lookupKey.substring( 1221040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX.length()); 1231040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki final long actualContactId = 1241040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki (contactId - ContactsContract.Contacts.ENTERPRISE_CONTACT_ID_BASE); 125494b95d30266335044a854845219b6e34cf43edbRicky Wai final long actualDirectoryId = (directoryId 126494b95d30266335044a854845219b6e34cf43edbRicky Wai - ContactsContract.Directory.ENTERPRISE_DIRECTORY_ID_BASE); 1271040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki 12897bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang dpm.startManagedQuickContact(actualLookupKey, actualContactId, isContactIdIgnored, 12997bdacc6d124f08a3f1c362fc35a5eed16af9880Victor Chang actualDirectoryId, originalIntent); 1301040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki return true; 1311040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki } 1321040da1d4eb99fd2588e4c4d5b08b2e3fc0c7777Makoto Onuki} 133