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