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