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 
17 package com.android.managedprovisioning.common;
18 
19 import android.accounts.Account;
20 import android.accounts.AccountManager;
21 import android.accounts.AccountManagerCallback;
22 import android.accounts.AccountManagerFuture;
23 import android.accounts.OperationCanceledException;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.ActivityInfo;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.IPackageManager;
30 import android.content.pm.PackageManager;
31 import android.content.pm.PackageManager.NameNotFoundException;
32 import android.content.pm.PackageInfo;
33 import android.content.pm.ParceledListSlice;
34 import android.content.pm.ResolveInfo;
35 import android.graphics.Color;
36 import android.net.ConnectivityManager;
37 import android.net.NetworkInfo;
38 import android.os.Build;
39 import android.os.Handler;
40 import android.os.UserHandle;
41 import android.test.AndroidTestCase;
42 import android.test.suitebuilder.annotation.SmallTest;
43 
44 import org.mockito.Mock;
45 import org.mockito.MockitoAnnotations;
46 
47 import java.util.Arrays;
48 import java.util.concurrent.TimeUnit;
49 import java.util.List;
50 import java.util.Set;
51 
52 import static org.mockito.Mockito.any;
53 import static org.mockito.Mockito.anyInt;
54 import static org.mockito.Mockito.anyLong;
55 import static org.mockito.Mockito.eq;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.verify;
58 import static org.mockito.Mockito.verifyNoMoreInteractions;
59 import static org.mockito.Mockito.verifyZeroInteractions;
60 import static org.mockito.Mockito.when;
61 
62 /**
63  * Unit-tests for {@link Utils}.
64  */
65 @SmallTest
66 public class UtilsTest extends AndroidTestCase {
67     private static final String TEST_PACKAGE_NAME_1 = "com.test.packagea";
68     private static final String TEST_PACKAGE_NAME_2 = "com.test.packageb";
69     private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(TEST_PACKAGE_NAME_1,
70             ".MainActivity");
71     private static final int TEST_USER_ID = 10;
72 
73     @Mock private Context mockContext;
74     @Mock private AccountManager mockAccountManager;
75     @Mock private IPackageManager mockIPackageManager;
76     @Mock private PackageManager mockPackageManager;
77     @Mock private ConnectivityManager mockConnectivityManager;
78 
79     private Utils mUtils;
80 
81     @Override
setUp()82     public void setUp() {
83         // this is necessary for mockito to work
84         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
85 
86         MockitoAnnotations.initMocks(this);
87 
88         when(mockContext.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mockAccountManager);
89         when(mockContext.getPackageManager()).thenReturn(mockPackageManager);
90         when(mockContext.getSystemService(Context.CONNECTIVITY_SERVICE))
91                 .thenReturn(mockConnectivityManager);
92 
93         mUtils = new Utils();
94     }
95 
testGetCurrentSystemApps()96     public void testGetCurrentSystemApps() throws Exception {
97         // GIVEN two currently installed apps, one of which is system
98         List<ApplicationInfo> appList = Arrays.asList(
99                 createApplicationInfo(TEST_PACKAGE_NAME_1, false),
100                 createApplicationInfo(TEST_PACKAGE_NAME_2, true));
101         when(mockIPackageManager.getInstalledApplications(
102                 PackageManager.GET_UNINSTALLED_PACKAGES, TEST_USER_ID))
103                 .thenReturn(new ParceledListSlice(appList));
104         // WHEN requesting the current system apps
105         Set<String> res = mUtils.getCurrentSystemApps(mockIPackageManager, TEST_USER_ID);
106         // THEN the one system app should be returned
107         assertEquals(1, res.size());
108         assertTrue(res.contains(TEST_PACKAGE_NAME_2));
109     }
110 
testSetComponentEnabledSetting()111     public void testSetComponentEnabledSetting() throws Exception {
112         // GIVEN a component name and a user id
113         // WHEN disabling a component
114         mUtils.setComponentEnabledSetting(mockIPackageManager, TEST_COMPONENT_NAME,
115                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, TEST_USER_ID);
116         // THEN the correct method on mockIPackageManager gets invoked
117         verify(mockIPackageManager).setComponentEnabledSetting(eq(TEST_COMPONENT_NAME),
118                 eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
119                 eq(PackageManager.DONT_KILL_APP),
120                 eq(TEST_USER_ID));
121         verifyNoMoreInteractions(mockIPackageManager);
122     }
123 
testPackageRequiresUpdate_notPresent()124     public void testPackageRequiresUpdate_notPresent() throws Exception {
125         // GIVEN that the requested package is not present on the device
126         // WHEN checking whether an update is required
127         when(mockPackageManager.getPackageInfo(TEST_PACKAGE_NAME_1, 0))
128                 .thenThrow(new NameNotFoundException());
129         // THEN an update is required
130         assertTrue(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 0, mockContext));
131     }
132 
testPackageRequiresUpdate()133     public void testPackageRequiresUpdate() throws Exception {
134         // GIVEN a package that is installed on the device
135         PackageInfo pi = new PackageInfo();
136         pi.packageName = TEST_PACKAGE_NAME_1;
137         pi.versionCode = 1;
138         when(mockPackageManager.getPackageInfo(TEST_PACKAGE_NAME_1, 0)).thenReturn(pi);
139         // WHEN checking whether an update is required
140         // THEN verify that update required returns the correct result depending on the minimum
141         // version code requested.
142         assertFalse(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 0, mockContext));
143         assertFalse(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 1, mockContext));
144         assertTrue(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 2, mockContext));
145     }
146 
testMaybeCopyAccount_success()147     public void testMaybeCopyAccount_success() throws Exception {
148         // GIVEN an account on the source user and a managed profile present and no timeout
149         // or error during migration
150         Account testAccount = new Account("test@afw-test.com", "com.google");
151         UserHandle primaryUser = UserHandle.of(0);
152         UserHandle managedProfile = UserHandle.of(10);
153 
154         AccountManagerFuture mockResult = mock(AccountManagerFuture.class);
155         when(mockResult.getResult(anyLong(), any(TimeUnit.class))).thenReturn(true);
156         when(mockAccountManager.copyAccountToUser(any(Account.class), any(UserHandle.class),
157                 any(UserHandle.class), any(AccountManagerCallback.class), any(Handler.class)))
158                 .thenReturn(mockResult);
159 
160         // WHEN copying the account from the source user to the target user
161         // THEN the account migration succeeds
162         assertTrue(mUtils.maybeCopyAccount(mockContext, testAccount, primaryUser, managedProfile));
163         verify(mockAccountManager).copyAccountToUser(eq(testAccount), eq(primaryUser),
164                 eq(managedProfile), any(AccountManagerCallback.class), any(Handler.class));
165         verify(mockResult).getResult(anyLong(), any(TimeUnit.class));
166     }
167 
testMaybeCopyAccount_error()168     public void testMaybeCopyAccount_error() throws Exception {
169         // GIVEN an account on the source user and a target user present and an error occurs
170         // during migration
171         Account testAccount = new Account("test@afw-test.com", "com.google");
172         UserHandle primaryUser = UserHandle.of(0);
173         UserHandle managedProfile = UserHandle.of(10);
174 
175         AccountManagerFuture mockResult = mock(AccountManagerFuture.class);
176         when(mockResult.getResult(anyLong(), any(TimeUnit.class))).thenReturn(false);
177         when(mockAccountManager.copyAccountToUser(any(Account.class), any(UserHandle.class),
178                 any(UserHandle.class), any(AccountManagerCallback.class), any(Handler.class)))
179                 .thenReturn(mockResult);
180 
181         // WHEN copying the account from the source user to the target user
182         // THEN the account migration fails
183         assertFalse(mUtils.maybeCopyAccount(mockContext, testAccount, primaryUser, managedProfile));
184         verify(mockAccountManager).copyAccountToUser(eq(testAccount), eq(primaryUser),
185                 eq(managedProfile), any(AccountManagerCallback.class), any(Handler.class));
186         verify(mockResult).getResult(anyLong(), any(TimeUnit.class));
187     }
188 
testMaybeCopyAccount_timeout()189     public void testMaybeCopyAccount_timeout() throws Exception {
190         // GIVEN an account on the source user and a target user present and a timeout occurs
191         // during migration
192         Account testAccount = new Account("test@afw-test.com", "com.google");
193         UserHandle primaryUser = UserHandle.of(0);
194         UserHandle managedProfile = UserHandle.of(10);
195 
196         AccountManagerFuture mockResult = mock(AccountManagerFuture.class);
197         // the AccountManagerFuture throws an OperationCanceledException after timeout
198         when(mockResult.getResult(anyLong(), any(TimeUnit.class)))
199                 .thenThrow(new OperationCanceledException());
200         when(mockAccountManager.copyAccountToUser(any(Account.class), any(UserHandle.class),
201                 any(UserHandle.class), any(AccountManagerCallback.class), any(Handler.class)))
202                 .thenReturn(mockResult);
203 
204         // WHEN copying the account from the source user to the target user
205         // THEN the account migration fails
206         assertFalse(mUtils.maybeCopyAccount(mockContext, testAccount, primaryUser, managedProfile));
207         verify(mockAccountManager).copyAccountToUser(eq(testAccount), eq(primaryUser),
208                 eq(managedProfile), any(AccountManagerCallback.class), any(Handler.class));
209         verify(mockResult).getResult(anyLong(), any(TimeUnit.class));
210     }
211 
testMaybeCopyAccount_nullAccount()212     public void testMaybeCopyAccount_nullAccount() {
213         // GIVEN a device with two users present
214         UserHandle primaryUser = UserHandle.of(0);
215         UserHandle managedProfile = UserHandle.of(10);
216 
217         // WHEN trying to copy a null account from the source user to the target user
218         // THEN request is ignored
219         assertFalse(mUtils.maybeCopyAccount(mockContext, null /* accountToMigrate */, primaryUser,
220                 managedProfile));
221         verifyZeroInteractions(mockAccountManager);
222     }
223 
testMaybeCopyAccount_sameUser()224     public void testMaybeCopyAccount_sameUser() {
225         // GIVEN an account on a user
226         Account testAccount = new Account("test@afw-test.com", "com.google");
227         UserHandle primaryUser = UserHandle.of(0);
228 
229         // WHEN trying to invoke copying an account with the same user id for source and target user
230         // THEN request is ignored
231         assertFalse(mUtils.maybeCopyAccount(mockContext, testAccount, primaryUser, primaryUser));
232         verifyZeroInteractions(mockAccountManager);
233     }
234 
testIsConnectedToNetwork()235     public void testIsConnectedToNetwork() throws Exception {
236         // GIVEN the device is currently connected to mobile network
237         setCurrentNetworkMock(ConnectivityManager.TYPE_MOBILE, true);
238         // WHEN checking connectivity
239         // THEN utils should return true
240         assertTrue(mUtils.isConnectedToNetwork(mockContext));
241 
242         // GIVEN the device is currently connected to wifi
243         setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, true);
244         // WHEN checking connectivity
245         // THEN utils should return true
246         assertTrue(mUtils.isConnectedToNetwork(mockContext));
247 
248         // GIVEN the device is currently disconnected on wifi
249         setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, false);
250         // WHEN checking connectivity
251         // THEN utils should return false
252         assertFalse(mUtils.isConnectedToNetwork(mockContext));
253     }
254 
testIsConnectedToWifi()255     public void testIsConnectedToWifi() throws Exception {
256         // GIVEN the device is currently connected to mobile network
257         setCurrentNetworkMock(ConnectivityManager.TYPE_MOBILE, true);
258         // WHEN checking whether connected to wifi
259         // THEN utils should return false
260         assertFalse(mUtils.isConnectedToWifi(mockContext));
261 
262         // GIVEN the device is currently connected to wifi
263         setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, true);
264         // WHEN checking whether connected to wifi
265         // THEN utils should return true
266         assertTrue(mUtils.isConnectedToWifi(mockContext));
267 
268         // GIVEN the device is currently disconnected on wifi
269         setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, false);
270         // WHEN checking whether connected to wifi
271         // THEN utils should return false
272         assertFalse(mUtils.isConnectedToWifi(mockContext));
273     }
274 
testCurrentLauncherSupportsManagedProfiles_noLauncherSet()275     public void testCurrentLauncherSupportsManagedProfiles_noLauncherSet() throws Exception {
276         // GIVEN there currently is no default launcher set
277         when(mockPackageManager.resolveActivity(any(Intent.class), anyInt()))
278                 .thenReturn(null);
279         // WHEN checking whether the current launcher support managed profiles
280         // THEN utils should return false
281         assertFalse(mUtils.currentLauncherSupportsManagedProfiles(mockContext));
282     }
283 
testCurrentLauncherSupportsManagedProfiles()284     public void testCurrentLauncherSupportsManagedProfiles() throws Exception {
285         // GIVEN the current default launcher is built against lollipop
286         setLauncherMock(Build.VERSION_CODES.LOLLIPOP);
287         // WHEN checking whether the current launcher support managed profiles
288         // THEN utils should return true
289         assertTrue(mUtils.currentLauncherSupportsManagedProfiles(mockContext));
290 
291         // GIVEN the current default launcher is built against kitkat
292         setLauncherMock(Build.VERSION_CODES.KITKAT);
293         // WHEN checking whether the current launcher support managed profiles
294         // THEN utils should return false
295         assertFalse(mUtils.currentLauncherSupportsManagedProfiles(mockContext));
296     }
297 
testBrightness()298     public void testBrightness() {
299         assertTrue(mUtils.isBrightColor(Color.WHITE));
300         assertTrue(mUtils.isBrightColor(Color.YELLOW));
301         assertFalse(mUtils.isBrightColor(Color.BLACK));
302         assertFalse(mUtils.isBrightColor(Color.BLUE));
303     }
304 
createApplicationInfo(String packageName, boolean system)305     private ApplicationInfo createApplicationInfo(String packageName, boolean system) {
306         ApplicationInfo ai = new ApplicationInfo();
307         ai.packageName = packageName;
308         if (system) {
309             ai.flags = ApplicationInfo.FLAG_SYSTEM;
310         }
311         return ai;
312     }
313 
setCurrentNetworkMock(int type, boolean connected)314     private void setCurrentNetworkMock(int type, boolean connected) {
315         NetworkInfo networkInfo = new NetworkInfo(type, 0, null, null);
316         networkInfo.setDetailedState(
317                 connected ? NetworkInfo.DetailedState.CONNECTED
318                         : NetworkInfo.DetailedState.DISCONNECTED,
319                 null, null);
320         when(mockConnectivityManager.getActiveNetworkInfo()).thenReturn(networkInfo);
321     }
322 
setLauncherMock(int targetSdkVersion)323     private void setLauncherMock(int targetSdkVersion) throws Exception {
324         ApplicationInfo appInfo = new ApplicationInfo();
325         appInfo.targetSdkVersion = targetSdkVersion;
326         ActivityInfo actInfo = new ActivityInfo();
327         actInfo.packageName = TEST_PACKAGE_NAME_1;
328         ResolveInfo resInfo = new ResolveInfo();
329         resInfo.activityInfo = actInfo;
330 
331         when(mockPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(resInfo);
332         when(mockPackageManager.getApplicationInfo(TEST_PACKAGE_NAME_1, 0)).thenReturn(appInfo);
333     }
334 }
335