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