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