Loading core/java/android/app/admin/DevicePolicyManager.java +16 −0 Original line number Original line Diff line number Diff line Loading @@ -3164,6 +3164,22 @@ public class DevicePolicyManager { return false; return false; } } /** * Start Quick Contact on the managed profile for the current user, if the policy allows. * @hide */ public void startManagedQuickContact(String actualLookupKey, long actualContactId, Intent originalIntent) { if (mService != null) { try { mService.startManagedQuickContact( actualLookupKey, actualContactId, originalIntent); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } } /** /** * Called by the profile owner of a managed profile so that some intents sent in the managed * Called by the profile owner of a managed profile so that some intents sent in the managed * profile can also be resolved in the parent, or vice versa. * profile can also be resolved in the parent, or vice versa. Loading core/java/android/app/admin/IDevicePolicyManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -189,6 +189,7 @@ interface IDevicePolicyManager { void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled); void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled); boolean getCrossProfileCallerIdDisabled(in ComponentName who); boolean getCrossProfileCallerIdDisabled(in ComponentName who); boolean getCrossProfileCallerIdDisabledForUser(int userId); boolean getCrossProfileCallerIdDisabledForUser(int userId); void startManagedQuickContact(String lookupKey, long contactId, in Intent originalIntent); void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent, void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent, in PersistableBundle args); in PersistableBundle args); Loading core/java/android/provider/ContactsContract.java +64 −21 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.provider; import android.accounts.Account; import android.accounts.Account; import android.app.Activity; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException; import android.content.ContentProviderClient; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentProviderOperation; Loading Loading @@ -1628,7 +1629,6 @@ public final class ContactsContract { */ */ public static final String CONTENT_VCARD_TYPE = "text/x-vcard"; public static final String CONTENT_VCARD_TYPE = "text/x-vcard"; /** /** * Mimimal ID for corp contacts returned from * Mimimal ID for corp contacts returned from * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}. * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}. Loading @@ -1637,6 +1637,14 @@ public final class ContactsContract { */ */ public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30 public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30 /** * Prefix for corp contacts returned from * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}. * * @hide */ public static String ENTERPRISE_CONTACT_LOOKUP_PREFIX = "c-"; /** /** * Return TRUE if a contact ID is from the contacts provider on the enterprise profile. * Return TRUE if a contact ID is from the contacts provider on the enterprise profile. * * Loading Loading @@ -5032,9 +5040,17 @@ public final class ContactsContract { * is from the corp profile, use * is from the corp profile, use * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * </li> * </li> * <li> * Corp contacts will get artificial {@link #LOOKUP_KEY}s too. * </li> * </ul> * </ul> * <p> * <p> * This URI does NOT support selection nor order-by. * A contact lookup URL built by * {@link ContactsContract.Contacts#getLookupUri(long, String)} * with an {@link #_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed to * {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the * corp profile. * </p> * * * <pre> * <pre> * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, Loading Loading @@ -6025,10 +6041,18 @@ public final class ContactsContract { * a contact * a contact * is from the corp profile, use * is from the corp profile, use * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * </li> * <li> * Corp contacts will get artificial {@link #LOOKUP_KEY}s too. * </li> * </li> * </ul> * </ul> * <p> * <p> * This URI does NOT support selection nor order-by. * A contact lookup URL built by * {@link ContactsContract.Contacts#getLookupUri(long, String)} * with an {@link #_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed to * {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the * corp profile. * </p> * * * <pre> * <pre> * Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI, * Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI, Loading Loading @@ -8182,6 +8206,9 @@ public final class ContactsContract { */ */ public static final int MODE_LARGE = 3; public static final int MODE_LARGE = 3; /** @hide */ public static final int MODE_DEFAULT = MODE_LARGE; /** /** * Constructs the QuickContacts intent with a view's rect. * Constructs the QuickContacts intent with a view's rect. * @hide * @hide Loading Loading @@ -8224,6 +8251,7 @@ public final class ContactsContract { // Launch pivot dialog through intent for now // Launch pivot dialog through intent for now final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags); final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags); // NOTE: This logic and rebuildManagedQuickContactsIntent() must be in sync. intent.setData(lookupUri); intent.setData(lookupUri); intent.setSourceBounds(target); intent.setSourceBounds(target); intent.putExtra(EXTRA_MODE, mode); intent.putExtra(EXTRA_MODE, mode); Loading @@ -8231,6 +8259,30 @@ public final class ContactsContract { return intent; return intent; } } /** * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager * to strip off anything not necessary. * * @hide */ public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId, Intent originalIntent) { final Intent intent = new Intent(ACTION_QUICK_CONTACT); // Rebuild the URI from a lookup key and a contact ID. intent.setData(Contacts.getLookupUri(contactId, lookupKey)); // Copy flags and always set NEW_TASK because it won't have a parent activity. intent.setFlags(originalIntent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); // Copy extras. intent.setSourceBounds(originalIntent.getSourceBounds()); intent.putExtra(EXTRA_MODE, originalIntent.getIntExtra(EXTRA_MODE, MODE_DEFAULT)); intent.putExtra(EXTRA_EXCLUDE_MIMES, originalIntent.getStringArrayExtra(EXTRA_EXCLUDE_MIMES)); return intent; } /** /** * Trigger a dialog that lists the various methods of interacting with * Trigger a dialog that lists the various methods of interacting with * the requested {@link Contacts} entry. This may be based on available * the requested {@link Contacts} entry. This may be based on available Loading Loading @@ -8259,7 +8311,7 @@ public final class ContactsContract { // Trigger with obtained rectangle // Trigger with obtained rectangle Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); excludeMimes); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } } /** /** Loading Loading @@ -8292,7 +8344,7 @@ public final class ContactsContract { String[] excludeMimes) { String[] excludeMimes) { Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); excludeMimes); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } } /** /** Loading Loading @@ -8325,10 +8377,10 @@ public final class ContactsContract { // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // values defined in ContactsContract only affect very old implementations // values defined in ContactsContract only affect very old implementations // of QuickContacts. // of QuickContacts. Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE, Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT, excludeMimes); excludeMimes); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } } /** /** Loading Loading @@ -8363,19 +8415,10 @@ public final class ContactsContract { // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // values defined in ContactsContract only affect very old implementations // values defined in ContactsContract only affect very old implementations // of QuickContacts. // of QuickContacts. Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE, Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT, excludeMimes); excludeMimes); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } private static void startActivityWithErrorToast(Context context, Intent intent) { try { context.startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, Toast.LENGTH_SHORT).show(); } } } } } Loading core/java/android/provider/ContactsInternal.java 0 → 100644 +112 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.provider; import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.UriMatcher; import android.net.Uri; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.widget.Toast; import java.util.List; /** * Contacts related internal methods. * * @hide */ public class ContactsInternal { private ContactsInternal() { } /** URI matcher used to parse contact URIs. */ private static final UriMatcher sContactsUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int CONTACTS_URI_LOOKUP_ID = 1000; static { // Contacts URI matching table final UriMatcher matcher = sContactsUriMatcher; matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_URI_LOOKUP_ID); } /** * Called by {@link ContactsContract} to star Quick Contact, possibly on the managed profile. */ public static void startQuickContactWithErrorToast(Context context, Intent intent) { final Uri uri = intent.getData(); final int match = sContactsUriMatcher.match(uri); switch (match) { case CONTACTS_URI_LOOKUP_ID: { if (maybeStartManagedQuickContact(context, intent)) { return; // Request handled by DPM. Just return here. } break; } } // Launch on the current profile. startQuickContactWithErrorToastForUser(context, intent, Process.myUserHandle()); } public static void startQuickContactWithErrorToastForUser(Context context, Intent intent, UserHandle user) { try { context.startActivityAsUser(intent, user); } catch (ActivityNotFoundException e) { Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, Toast.LENGTH_SHORT).show(); } } /** * If the URI in {@code intent} is of a corp contact, launch quick contact on the managed * profile. * * @return the URI in {@code intent} is of a corp contact thus launched on the managed profile. */ private static boolean maybeStartManagedQuickContact(Context context, Intent originalIntent) { final Uri uri = originalIntent.getData(); // Decompose into an ID and a lookup key. final List<String> pathSegments = uri.getPathSegments(); final long contactId = ContentUris.parseId(uri); final String lookupKey = pathSegments.get(2); // See if it has a corp lookupkey. if (TextUtils.isEmpty(lookupKey) || !lookupKey.startsWith( ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX)) { return false; // It's not a corp lookup key. } // Launch Quick Contact on the managed profile, if the policy allows. final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); final String actualLookupKey = lookupKey.substring( ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX.length()); final long actualContactId = (contactId - ContactsContract.Contacts.ENTERPRISE_CONTACT_ID_BASE); dpm.startManagedQuickContact(actualLookupKey, actualContactId, originalIntent); return true; } } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +57 −0 Original line number Original line Diff line number Diff line Loading @@ -78,6 +78,8 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; import android.provider.Settings; import android.security.Credentials; import android.security.Credentials; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainAliasCallback; Loading Loading @@ -146,6 +148,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String LOG_TAG = "DevicePolicyManagerService"; private static final String LOG_TAG = "DevicePolicyManagerService"; private static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE private static final String DEVICE_POLICIES_XML = "device_policies.xml"; private static final String DEVICE_POLICIES_XML = "device_policies.xml"; private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component"; private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component"; Loading Loading @@ -5435,6 +5439,59 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } } @Override public void startManagedQuickContact(String actualLookupKey, long actualContactId, Intent originalIntent) { final Intent intent = QuickContact.rebuildManagedQuickContactsIntent( actualLookupKey, actualContactId, originalIntent); final int callingUserId = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { synchronized (this) { final int managedUserId = getManagedUserId(callingUserId); if (managedUserId < 0) { return; } if (getCrossProfileCallerIdDisabledForUser(managedUserId)) { if (VERBOSE_LOG) { Log.v(LOG_TAG, "Cross-profile contacts access disabled for user " + managedUserId); } return; } ContactsInternal.startQuickContactWithErrorToastForUser( mContext, intent, new UserHandle(managedUserId)); } } finally { Binder.restoreCallingIdentity(ident); } } /** * @return the user ID of the managed user that is linked to the current user, if any. * Otherwise -1. */ public int getManagedUserId(int callingUserId) { if (VERBOSE_LOG) { Log.v(LOG_TAG, "getManagedUserId: callingUserId=" + callingUserId); } for (UserInfo ui : mUserManager.getProfiles(callingUserId)) { if (ui.id == callingUserId || !ui.isManagedProfile()) { continue; // Caller user self, or not a managed profile. Skip. } if (VERBOSE_LOG) { Log.v(LOG_TAG, "Managed user=" + ui.id); } return ui.id; } if (VERBOSE_LOG) { Log.v(LOG_TAG, "Managed user not found."); } return -1; } /** /** * Sets which packages may enter lock task mode. * Sets which packages may enter lock task mode. * * Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +16 −0 Original line number Original line Diff line number Diff line Loading @@ -3164,6 +3164,22 @@ public class DevicePolicyManager { return false; return false; } } /** * Start Quick Contact on the managed profile for the current user, if the policy allows. * @hide */ public void startManagedQuickContact(String actualLookupKey, long actualContactId, Intent originalIntent) { if (mService != null) { try { mService.startManagedQuickContact( actualLookupKey, actualContactId, originalIntent); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } } /** /** * Called by the profile owner of a managed profile so that some intents sent in the managed * Called by the profile owner of a managed profile so that some intents sent in the managed * profile can also be resolved in the parent, or vice versa. * profile can also be resolved in the parent, or vice versa. Loading
core/java/android/app/admin/IDevicePolicyManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -189,6 +189,7 @@ interface IDevicePolicyManager { void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled); void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled); boolean getCrossProfileCallerIdDisabled(in ComponentName who); boolean getCrossProfileCallerIdDisabled(in ComponentName who); boolean getCrossProfileCallerIdDisabledForUser(int userId); boolean getCrossProfileCallerIdDisabledForUser(int userId); void startManagedQuickContact(String lookupKey, long contactId, in Intent originalIntent); void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent, void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent, in PersistableBundle args); in PersistableBundle args); Loading
core/java/android/provider/ContactsContract.java +64 −21 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.provider; import android.accounts.Account; import android.accounts.Account; import android.app.Activity; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException; import android.content.ContentProviderClient; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentProviderOperation; Loading Loading @@ -1628,7 +1629,6 @@ public final class ContactsContract { */ */ public static final String CONTENT_VCARD_TYPE = "text/x-vcard"; public static final String CONTENT_VCARD_TYPE = "text/x-vcard"; /** /** * Mimimal ID for corp contacts returned from * Mimimal ID for corp contacts returned from * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}. * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}. Loading @@ -1637,6 +1637,14 @@ public final class ContactsContract { */ */ public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30 public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30 /** * Prefix for corp contacts returned from * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}. * * @hide */ public static String ENTERPRISE_CONTACT_LOOKUP_PREFIX = "c-"; /** /** * Return TRUE if a contact ID is from the contacts provider on the enterprise profile. * Return TRUE if a contact ID is from the contacts provider on the enterprise profile. * * Loading Loading @@ -5032,9 +5040,17 @@ public final class ContactsContract { * is from the corp profile, use * is from the corp profile, use * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * </li> * </li> * <li> * Corp contacts will get artificial {@link #LOOKUP_KEY}s too. * </li> * </ul> * </ul> * <p> * <p> * This URI does NOT support selection nor order-by. * A contact lookup URL built by * {@link ContactsContract.Contacts#getLookupUri(long, String)} * with an {@link #_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed to * {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the * corp profile. * </p> * * * <pre> * <pre> * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, Loading Loading @@ -6025,10 +6041,18 @@ public final class ContactsContract { * a contact * a contact * is from the corp profile, use * is from the corp profile, use * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * {@link ContactsContract.Contacts#isEnterpriseContactId(long)}. * </li> * <li> * Corp contacts will get artificial {@link #LOOKUP_KEY}s too. * </li> * </li> * </ul> * </ul> * <p> * <p> * This URI does NOT support selection nor order-by. * A contact lookup URL built by * {@link ContactsContract.Contacts#getLookupUri(long, String)} * with an {@link #_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed to * {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the * corp profile. * </p> * * * <pre> * <pre> * Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI, * Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI, Loading Loading @@ -8182,6 +8206,9 @@ public final class ContactsContract { */ */ public static final int MODE_LARGE = 3; public static final int MODE_LARGE = 3; /** @hide */ public static final int MODE_DEFAULT = MODE_LARGE; /** /** * Constructs the QuickContacts intent with a view's rect. * Constructs the QuickContacts intent with a view's rect. * @hide * @hide Loading Loading @@ -8224,6 +8251,7 @@ public final class ContactsContract { // Launch pivot dialog through intent for now // Launch pivot dialog through intent for now final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags); final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags); // NOTE: This logic and rebuildManagedQuickContactsIntent() must be in sync. intent.setData(lookupUri); intent.setData(lookupUri); intent.setSourceBounds(target); intent.setSourceBounds(target); intent.putExtra(EXTRA_MODE, mode); intent.putExtra(EXTRA_MODE, mode); Loading @@ -8231,6 +8259,30 @@ public final class ContactsContract { return intent; return intent; } } /** * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager * to strip off anything not necessary. * * @hide */ public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId, Intent originalIntent) { final Intent intent = new Intent(ACTION_QUICK_CONTACT); // Rebuild the URI from a lookup key and a contact ID. intent.setData(Contacts.getLookupUri(contactId, lookupKey)); // Copy flags and always set NEW_TASK because it won't have a parent activity. intent.setFlags(originalIntent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); // Copy extras. intent.setSourceBounds(originalIntent.getSourceBounds()); intent.putExtra(EXTRA_MODE, originalIntent.getIntExtra(EXTRA_MODE, MODE_DEFAULT)); intent.putExtra(EXTRA_EXCLUDE_MIMES, originalIntent.getStringArrayExtra(EXTRA_EXCLUDE_MIMES)); return intent; } /** /** * Trigger a dialog that lists the various methods of interacting with * Trigger a dialog that lists the various methods of interacting with * the requested {@link Contacts} entry. This may be based on available * the requested {@link Contacts} entry. This may be based on available Loading Loading @@ -8259,7 +8311,7 @@ public final class ContactsContract { // Trigger with obtained rectangle // Trigger with obtained rectangle Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); excludeMimes); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } } /** /** Loading Loading @@ -8292,7 +8344,7 @@ public final class ContactsContract { String[] excludeMimes) { String[] excludeMimes) { Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); excludeMimes); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } } /** /** Loading Loading @@ -8325,10 +8377,10 @@ public final class ContactsContract { // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // values defined in ContactsContract only affect very old implementations // values defined in ContactsContract only affect very old implementations // of QuickContacts. // of QuickContacts. Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE, Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT, excludeMimes); excludeMimes); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } } /** /** Loading Loading @@ -8363,19 +8415,10 @@ public final class ContactsContract { // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // Use MODE_LARGE instead of accepting mode as a parameter. The different mode // values defined in ContactsContract only affect very old implementations // values defined in ContactsContract only affect very old implementations // of QuickContacts. // of QuickContacts. Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE, Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT, excludeMimes); excludeMimes); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType); startActivityWithErrorToast(context, intent); ContactsInternal.startQuickContactWithErrorToast(context, intent); } private static void startActivityWithErrorToast(Context context, Intent intent) { try { context.startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, Toast.LENGTH_SHORT).show(); } } } } } Loading
core/java/android/provider/ContactsInternal.java 0 → 100644 +112 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.provider; import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.UriMatcher; import android.net.Uri; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.widget.Toast; import java.util.List; /** * Contacts related internal methods. * * @hide */ public class ContactsInternal { private ContactsInternal() { } /** URI matcher used to parse contact URIs. */ private static final UriMatcher sContactsUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int CONTACTS_URI_LOOKUP_ID = 1000; static { // Contacts URI matching table final UriMatcher matcher = sContactsUriMatcher; matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_URI_LOOKUP_ID); } /** * Called by {@link ContactsContract} to star Quick Contact, possibly on the managed profile. */ public static void startQuickContactWithErrorToast(Context context, Intent intent) { final Uri uri = intent.getData(); final int match = sContactsUriMatcher.match(uri); switch (match) { case CONTACTS_URI_LOOKUP_ID: { if (maybeStartManagedQuickContact(context, intent)) { return; // Request handled by DPM. Just return here. } break; } } // Launch on the current profile. startQuickContactWithErrorToastForUser(context, intent, Process.myUserHandle()); } public static void startQuickContactWithErrorToastForUser(Context context, Intent intent, UserHandle user) { try { context.startActivityAsUser(intent, user); } catch (ActivityNotFoundException e) { Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, Toast.LENGTH_SHORT).show(); } } /** * If the URI in {@code intent} is of a corp contact, launch quick contact on the managed * profile. * * @return the URI in {@code intent} is of a corp contact thus launched on the managed profile. */ private static boolean maybeStartManagedQuickContact(Context context, Intent originalIntent) { final Uri uri = originalIntent.getData(); // Decompose into an ID and a lookup key. final List<String> pathSegments = uri.getPathSegments(); final long contactId = ContentUris.parseId(uri); final String lookupKey = pathSegments.get(2); // See if it has a corp lookupkey. if (TextUtils.isEmpty(lookupKey) || !lookupKey.startsWith( ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX)) { return false; // It's not a corp lookup key. } // Launch Quick Contact on the managed profile, if the policy allows. final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); final String actualLookupKey = lookupKey.substring( ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX.length()); final long actualContactId = (contactId - ContactsContract.Contacts.ENTERPRISE_CONTACT_ID_BASE); dpm.startManagedQuickContact(actualLookupKey, actualContactId, originalIntent); return true; } }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +57 −0 Original line number Original line Diff line number Diff line Loading @@ -78,6 +78,8 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; import android.provider.Settings; import android.security.Credentials; import android.security.Credentials; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainAliasCallback; Loading Loading @@ -146,6 +148,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String LOG_TAG = "DevicePolicyManagerService"; private static final String LOG_TAG = "DevicePolicyManagerService"; private static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE private static final String DEVICE_POLICIES_XML = "device_policies.xml"; private static final String DEVICE_POLICIES_XML = "device_policies.xml"; private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component"; private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component"; Loading Loading @@ -5435,6 +5439,59 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } } @Override public void startManagedQuickContact(String actualLookupKey, long actualContactId, Intent originalIntent) { final Intent intent = QuickContact.rebuildManagedQuickContactsIntent( actualLookupKey, actualContactId, originalIntent); final int callingUserId = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { synchronized (this) { final int managedUserId = getManagedUserId(callingUserId); if (managedUserId < 0) { return; } if (getCrossProfileCallerIdDisabledForUser(managedUserId)) { if (VERBOSE_LOG) { Log.v(LOG_TAG, "Cross-profile contacts access disabled for user " + managedUserId); } return; } ContactsInternal.startQuickContactWithErrorToastForUser( mContext, intent, new UserHandle(managedUserId)); } } finally { Binder.restoreCallingIdentity(ident); } } /** * @return the user ID of the managed user that is linked to the current user, if any. * Otherwise -1. */ public int getManagedUserId(int callingUserId) { if (VERBOSE_LOG) { Log.v(LOG_TAG, "getManagedUserId: callingUserId=" + callingUserId); } for (UserInfo ui : mUserManager.getProfiles(callingUserId)) { if (ui.id == callingUserId || !ui.isManagedProfile()) { continue; // Caller user self, or not a managed profile. Skip. } if (VERBOSE_LOG) { Log.v(LOG_TAG, "Managed user=" + ui.id); } return ui.id; } if (VERBOSE_LOG) { Log.v(LOG_TAG, "Managed user not found."); } return -1; } /** /** * Sets which packages may enter lock task mode. * Sets which packages may enter lock task mode. * * Loading