1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.providers.contacts.enterprise; 17 18 import android.app.admin.DevicePolicyManager; 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.content.pm.UserInfo; 22 import android.net.Uri; 23 import android.os.UserHandle; 24 import android.os.UserManager; 25 import android.provider.ContactsContract; 26 import android.provider.ContactsContract.Directory; 27 import android.test.AndroidTestCase; 28 import android.test.mock.MockContext; 29 import android.test.suitebuilder.annotation.SmallTest; 30 31 import org.mockito.Matchers; 32 33 import java.util.Arrays; 34 import java.util.List; 35 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.when; 38 39 40 /** 41 * Unit tests for {@link EnterprisePolicyGuard}. 42 */ 43 @SmallTest 44 public class EnterprisePolicyGuardTest extends AndroidTestCase { 45 private static final String SYSTEM_PROPERTY_DEXMAKER_DEXCACHE = "dexmaker.dexcache"; 46 47 private static final int CONTACT_ID = 10; 48 private static final String CONTACT_NAME = "david"; 49 private static final String CONTACT_EMAIL = "david.green@android.com"; 50 private static final String CONTACT_PHONE = "+1234567890"; 51 private static final long DIRECTORY_ID = Directory.ENTERPRISE_DEFAULT; 52 53 private static final Uri URI_CONTACTS_ID_PHOTO = 54 Uri.parse("content://com.android.contacts/contacts/" + CONTACT_ID + "/photo"); 55 private static final Uri URI_CONTACTS_ID_DISPLAY_PHOTO = Uri 56 .parse("content://com.android.contacts/contacts/" + CONTACT_ID + "/display_photo"); 57 private static final Uri URI_CONTACTS_FILTER = 58 Uri.parse("content://com.android.contacts/contacts/filter/" + CONTACT_NAME); 59 private static final Uri URI_PHONES_FILTER = Uri 60 .parse("content://com.android.contacts/data/phones/filter/" + CONTACT_NAME); 61 private static final Uri URI_CALLABLES_FILTER = Uri.parse( 62 "content://com.android.contacts/data/callables/filter/" + CONTACT_NAME); 63 private static final Uri URI_EMAILS_FILTER = Uri 64 .parse("content://com.android.contacts/data/emails/filter/" + CONTACT_NAME); 65 private static final Uri URI_EMAILS_LOOKUP = 66 Uri.parse("content://com.android.contacts/data/emails/lookup/" 67 + Uri.encode(CONTACT_EMAIL)); 68 private static final Uri URI_PHONE_LOOKUP = Uri.parse( 69 "content://com.android.contacts/phone_lookup/" + Uri.encode(CONTACT_PHONE)); 70 private static final Uri URI_DIRECTORIES = 71 Uri.parse("content://com.android.contacts/directories"); 72 private static final Uri URI_DIRECTORIES_ID = 73 Uri.parse("content://com.android.contacts/directories/" + DIRECTORY_ID); 74 private static final Uri URI_DIRECTORY_FILE = 75 Uri.parse("content://com.android.contacts/directory_file_enterprise/content%3A%2F%2F" 76 + "com.google.contacts.gal.provider%2Fphoto%2F?directory=1000000002"); 77 78 private static final Uri URI_OTHER = 79 Uri.parse("content://com.android.contacts/contacts/" + CONTACT_ID); 80 81 // Please notice that the directory id should be < ENTERPRISE_BASE because the id should be 82 // substracted before passing to enterprise side. 83 private static final int REMOTE_DIRECTORY_ID = 10; 84 85 @Override setUp()86 protected void setUp() throws Exception { 87 super.setUp(); 88 System.setProperty(SYSTEM_PROPERTY_DEXMAKER_DEXCACHE, getContext().getCacheDir().getPath()); 89 Thread.currentThread().setContextClassLoader(EnterprisePolicyGuard.class.getClassLoader()); 90 } 91 92 @Override tearDown()93 protected void tearDown() throws Exception { 94 super.tearDown(); 95 System.clearProperty(SYSTEM_PROPERTY_DEXMAKER_DEXCACHE); 96 } 97 testDirectorySupport()98 public void testDirectorySupport() { 99 EnterprisePolicyGuard guard = new EnterprisePolicyGuardTestable(getContext(), true); 100 checkDirectorySupport(guard, URI_PHONE_LOOKUP, true); 101 checkDirectorySupport(guard, URI_EMAILS_LOOKUP, true); 102 checkDirectorySupport(guard, URI_CONTACTS_FILTER, true); 103 checkDirectorySupport(guard, URI_PHONES_FILTER, true); 104 checkDirectorySupport(guard, URI_CALLABLES_FILTER, true); 105 checkDirectorySupport(guard, URI_EMAILS_FILTER, true); 106 checkDirectorySupport(guard, URI_DIRECTORY_FILE, true); 107 checkDirectorySupport(guard, URI_DIRECTORIES, false); 108 checkDirectorySupport(guard, URI_DIRECTORIES_ID, false); 109 checkDirectorySupport(guard, URI_CONTACTS_ID_PHOTO, false); 110 checkDirectorySupport(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, false); 111 checkDirectorySupport(guard, URI_OTHER, false); 112 } 113 114 testCrossProfile_userSettingOn()115 public void testCrossProfile_userSettingOn() { 116 Context context; 117 EnterprisePolicyGuard guard; 118 // All enabled. 119 context = getMockContext(true, true); 120 guard = new EnterprisePolicyGuardTestable(context, true); 121 checkCrossProfile(guard, URI_PHONE_LOOKUP, true); 122 checkCrossProfile(guard, URI_EMAILS_LOOKUP, true); 123 checkCrossProfile(guard, URI_CONTACTS_FILTER, true); 124 checkCrossProfile(guard, URI_PHONES_FILTER, true); 125 checkCrossProfile(guard, URI_CALLABLES_FILTER, true); 126 checkCrossProfile(guard, URI_EMAILS_FILTER, true); 127 checkCrossProfile(guard, URI_DIRECTORY_FILE, true); 128 checkCrossProfile(guard, URI_DIRECTORIES, true); 129 checkCrossProfile(guard, URI_DIRECTORIES_ID, true); 130 checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, true); 131 checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, true); 132 checkCrossProfile(guard, URI_OTHER, false); 133 134 // Only ContactsSearch is disabled 135 context = getMockContext(true, /* isContactsSearchEnabled= */ false); 136 guard = new EnterprisePolicyGuardTestable(context, true); 137 checkCrossProfile(guard, URI_PHONE_LOOKUP, true); 138 checkCrossProfile(guard, URI_EMAILS_LOOKUP, true); 139 checkCrossProfile(guard, URI_CONTACTS_FILTER, false); 140 checkCrossProfile(guard, URI_PHONES_FILTER, false); 141 checkCrossProfile(guard, URI_CALLABLES_FILTER, false); 142 checkCrossProfile(guard, URI_EMAILS_FILTER, false); 143 checkCrossProfile(guard, URI_DIRECTORY_FILE, true); 144 checkCrossProfile(guard, URI_DIRECTORIES, true); 145 checkCrossProfile(guard, URI_DIRECTORIES_ID, true); 146 checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, true); 147 checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, true); 148 checkCrossProfile(guard, URI_OTHER, false); 149 150 // Only CallerId is disabled 151 context = getMockContext(/* isCallerIdEnabled= */ false, true); 152 guard = new EnterprisePolicyGuardTestable(context, true); 153 checkCrossProfile(guard, URI_PHONE_LOOKUP, false); 154 checkCrossProfile(guard, URI_EMAILS_LOOKUP, false); 155 checkCrossProfile(guard, URI_CONTACTS_FILTER, true); 156 checkCrossProfile(guard, URI_PHONES_FILTER, true); 157 checkCrossProfile(guard, URI_CALLABLES_FILTER, true); 158 checkCrossProfile(guard, URI_EMAILS_FILTER, true); 159 checkCrossProfile(guard, URI_DIRECTORY_FILE, true); 160 checkCrossProfile(guard, URI_DIRECTORIES, true); 161 checkCrossProfile(guard, URI_DIRECTORIES_ID, true); 162 checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, true); 163 checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, true); 164 checkCrossProfile(guard, URI_OTHER, false); 165 166 // CallerId and ContactsSearch are disabled 167 context = getMockContext(/* isCallerIdEnabled= */ false, 168 /* isContactsSearchEnabled= */ false); 169 guard = new EnterprisePolicyGuardTestable(context, true); 170 checkCrossProfile(guard, URI_PHONE_LOOKUP, false); 171 checkCrossProfile(guard, URI_EMAILS_LOOKUP, false); 172 checkCrossProfile(guard, URI_CONTACTS_FILTER, false); 173 checkCrossProfile(guard, URI_PHONES_FILTER, false); 174 checkCrossProfile(guard, URI_CALLABLES_FILTER, false); 175 checkCrossProfile(guard, URI_EMAILS_FILTER, false); 176 checkCrossProfile(guard, URI_DIRECTORY_FILE, false); 177 checkCrossProfile(guard, URI_DIRECTORIES, false); 178 checkCrossProfile(guard, URI_DIRECTORIES_ID, false); 179 checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, false); 180 checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, false); 181 checkCrossProfile(guard, URI_OTHER, false); 182 } 183 testCrossProfile_userSettingOff()184 public void testCrossProfile_userSettingOff() { 185 // All enabled. 186 Context context = getMockContext(true, true); 187 EnterprisePolicyGuard guard = new EnterprisePolicyGuardTestable(context, false); 188 // All directory supported Uris with remote directory id should not allowed. 189 checkCrossProfile(guard, appendRemoteDirectoryId(URI_PHONE_LOOKUP), false); 190 checkCrossProfile(guard, appendRemoteDirectoryId(URI_EMAILS_LOOKUP), false); 191 checkCrossProfile(guard, appendRemoteDirectoryId(URI_CONTACTS_FILTER), false); 192 checkCrossProfile(guard, appendRemoteDirectoryId(URI_PHONES_FILTER), false); 193 checkCrossProfile(guard, appendRemoteDirectoryId(URI_CALLABLES_FILTER), false); 194 checkCrossProfile(guard, appendRemoteDirectoryId(URI_EMAILS_FILTER), false); 195 checkCrossProfile(guard, URI_DIRECTORY_FILE, false); 196 197 // Always allow uri with no directory support. 198 checkCrossProfile(guard, URI_DIRECTORIES, true); 199 checkCrossProfile(guard, URI_DIRECTORIES_ID, true); 200 checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, true); 201 checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, true); 202 checkCrossProfile(guard, URI_OTHER, false); 203 204 // Always allow uri with no remote directory id. 205 checkCrossProfile(guard, URI_PHONE_LOOKUP, true); 206 checkCrossProfile(guard, URI_EMAILS_LOOKUP, true); 207 checkCrossProfile(guard, URI_CONTACTS_FILTER, true); 208 checkCrossProfile(guard, URI_PHONES_FILTER, true); 209 checkCrossProfile(guard, URI_CALLABLES_FILTER, true); 210 checkCrossProfile(guard, URI_EMAILS_FILTER, true); 211 } 212 appendRemoteDirectoryId(Uri uri)213 private static Uri appendRemoteDirectoryId(Uri uri) { 214 return appendDirectoryId(uri, REMOTE_DIRECTORY_ID); 215 } 216 appendDirectoryId(Uri uri, int directoryId)217 private static Uri appendDirectoryId(Uri uri, int directoryId) { 218 return uri.buildUpon().appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 219 String.valueOf(directoryId)).build(); 220 } 221 222 checkDirectorySupport(EnterprisePolicyGuard guard, Uri uri, boolean expected)223 private static void checkDirectorySupport(EnterprisePolicyGuard guard, Uri uri, 224 boolean expected) { 225 if (expected) { 226 assertTrue("Expected true but got false for uri: " + uri, 227 guard.isCrossProfileDirectorySupported(uri)); 228 } else { 229 assertFalse("Expected false but got true for uri: " + uri, 230 guard.isCrossProfileDirectorySupported(uri)); 231 } 232 } 233 checkCrossProfile(EnterprisePolicyGuard guard, Uri uri, boolean expected)234 private static void checkCrossProfile(EnterprisePolicyGuard guard, Uri uri, boolean expected) { 235 if (expected) { 236 assertTrue("Expected true but got false for uri: " + uri, 237 guard.isCrossProfileAllowed(uri)); 238 } else { 239 assertFalse("Expected false but got true for uri: " + uri, 240 guard.isCrossProfileAllowed(uri)); 241 } 242 } 243 244 private static final int CURRENT_USER_ID = 0; 245 private static final int WORK_USER_ID = 10; 246 private static final UserInfo CURRENT_USER_INFO = 247 new UserInfo(CURRENT_USER_ID, "user0", CURRENT_USER_ID); 248 private static final UserInfo WORK_USER_INFO = 249 new UserInfo(WORK_USER_ID, "user10", UserInfo.FLAG_MANAGED_PROFILE); 250 251 private static final List<UserInfo> NORMAL_USERINFO_LIST = 252 Arrays.asList(new UserInfo[] {CURRENT_USER_INFO}); 253 254 private static final List<UserInfo> MANAGED_USERINFO_LIST = 255 Arrays.asList(new UserInfo[] {CURRENT_USER_INFO, WORK_USER_INFO}); 256 257 getMockContext(boolean isCallerIdEnabled, boolean isContactsSearchEnabled)258 private Context getMockContext(boolean isCallerIdEnabled, boolean isContactsSearchEnabled) { 259 DevicePolicyManager mockDpm = mock(DevicePolicyManager.class); 260 when(mockDpm.getCrossProfileCallerIdDisabled(Matchers.<UserHandle>any())) 261 .thenReturn(!isCallerIdEnabled); 262 when(mockDpm.getCrossProfileContactsSearchDisabled(Matchers.<UserHandle>any())) 263 .thenReturn(!isContactsSearchEnabled); 264 265 List<UserInfo> userInfos = MANAGED_USERINFO_LIST; 266 UserManager mockUm = mock(UserManager.class); 267 when(mockUm.getUserHandle()).thenReturn(CURRENT_USER_ID); 268 when(mockUm.getUsers()).thenReturn(userInfos); 269 when(mockUm.getProfiles(Matchers.anyInt())).thenReturn(userInfos); 270 when(mockUm.getProfileParent(WORK_USER_ID)).thenReturn(CURRENT_USER_INFO); 271 272 Context mockContext = new TestMockContext(getContext(), mockDpm, mockUm); 273 274 return mockContext; 275 } 276 277 private static final class TestMockContext extends MockContext { 278 private Context mRealContext; 279 private DevicePolicyManager mDpm; 280 private UserManager mUm; 281 TestMockContext(Context realContext, DevicePolicyManager dpm, UserManager um)282 public TestMockContext(Context realContext, DevicePolicyManager dpm, UserManager um) { 283 mRealContext = realContext; 284 mDpm = dpm; 285 mUm = um; 286 } 287 getSystemService(String name)288 public Object getSystemService(String name) { 289 if (Context.DEVICE_POLICY_SERVICE.equals(name)) { 290 return mDpm; 291 } else if (Context.USER_SERVICE.equals(name)) { 292 return mUm; 293 } else { 294 return super.getSystemService(name); 295 } 296 } 297 getSystemServiceName(Class<?> serviceClass)298 public String getSystemServiceName(Class<?> serviceClass) { 299 return mRealContext.getSystemServiceName(serviceClass); 300 } 301 } 302 303 private static class EnterprisePolicyGuardTestable extends EnterprisePolicyGuard { 304 private boolean mIsContactRemoteSearchUserSettingEnabled; 305 EnterprisePolicyGuardTestable(Context context, boolean isContactRemoteSearchUserSettingEnabled)306 public EnterprisePolicyGuardTestable(Context context, 307 boolean isContactRemoteSearchUserSettingEnabled) { 308 super(context); 309 mIsContactRemoteSearchUserSettingEnabled = isContactRemoteSearchUserSettingEnabled; 310 } 311 312 @Override isContactRemoteSearchUserSettingEnabled()313 protected boolean isContactRemoteSearchUserSettingEnabled() { 314 return mIsContactRemoteSearchUserSettingEnabled; 315 } 316 } 317 318 } 319