/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.managedprovisioning.common; import static android.content.pm.PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.accounts.AccountManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.FileOutputStream; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * Unit-tests for {@link Utils}. */ @SmallTest public class UtilsTest extends AndroidTestCase { private static final String TEST_PACKAGE_NAME_1 = "com.test.packagea"; private static final String TEST_PACKAGE_NAME_2 = "com.test.packageb"; private static final String TEST_PACKAGE_NAME_3 = "com.test.packagec"; private static final String TEST_DEVICE_ADMIN_NAME = TEST_PACKAGE_NAME_1 + ".DeviceAdmin"; // Another DeviceAdmin in package 1 private static final String TEST_DEVICE_ADMIN_NAME_2 = TEST_PACKAGE_NAME_1 + ".DeviceAdmin2"; private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME); private static final ComponentName TEST_COMPONENT_NAME_2 = new ComponentName(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME_2); private static final int TEST_USER_ID = 10; private static final String TEST_FILE_NAME = "testfile"; @Mock private Context mockContext; @Mock private AccountManager mockAccountManager; @Mock private IPackageManager mockIPackageManager; @Mock private PackageManager mockPackageManager; @Mock private ConnectivityManager mockConnectivityManager; private Utils mUtils; @Override public void setUp() { // this is necessary for mockito to work System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); MockitoAnnotations.initMocks(this); when(mockContext.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mockAccountManager); when(mockContext.getPackageManager()).thenReturn(mockPackageManager); when(mockContext.getSystemService(Context.CONNECTIVITY_SERVICE)) .thenReturn(mockConnectivityManager); mUtils = new Utils(); } @Override public void tearDown() { mContext.deleteFile(TEST_FILE_NAME); } public void testGetCurrentSystemApps() throws Exception { // GIVEN two currently installed apps, one of which is system final List systemAppsWithHiddenUntilInstalled = Arrays.asList( createApplicationInfo( TEST_PACKAGE_NAME_1, /* system */ false, /* hiddenUntilInstalled */ false), createApplicationInfo( TEST_PACKAGE_NAME_2, /* system */ true, /* hiddenUntilInstalled */ false), createApplicationInfo( TEST_PACKAGE_NAME_3, /* system */ true, /* hiddenUntilInstalled */ true)); final List systemApps = systemAppsWithHiddenUntilInstalled.stream() .filter(applicationInfo -> !applicationInfo.hiddenUntilInstalled) .collect(Collectors.toList()); when(mockIPackageManager.getInstalledApplications( MATCH_UNINSTALLED_PACKAGES, TEST_USER_ID)) .thenReturn(new ParceledListSlice<>(systemApps)); when(mockIPackageManager.getInstalledApplications( MATCH_UNINSTALLED_PACKAGES | MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, TEST_USER_ID)) .thenReturn(new ParceledListSlice<>(systemAppsWithHiddenUntilInstalled)); // WHEN requesting the current system apps Set res = mUtils.getCurrentSystemApps(mockIPackageManager, TEST_USER_ID); // THEN two system apps should be returned assertEquals(2, res.size()); assertTrue(res.contains(TEST_PACKAGE_NAME_2)); assertTrue(res.contains(TEST_PACKAGE_NAME_3)); } public void testSetComponentEnabledSetting() throws Exception { // GIVEN a component name and a user id // WHEN disabling a component mUtils.setComponentEnabledSetting(mockIPackageManager, TEST_COMPONENT_NAME, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, TEST_USER_ID); // THEN the correct method on mockIPackageManager gets invoked verify(mockIPackageManager).setComponentEnabledSetting(eq(TEST_COMPONENT_NAME), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.DONT_KILL_APP), eq(TEST_USER_ID)); verifyNoMoreInteractions(mockIPackageManager); } public void testPackageRequiresUpdate_notPresent() throws Exception { // GIVEN that the requested package is not present on the device // WHEN checking whether an update is required when(mockPackageManager.getPackageInfo(TEST_PACKAGE_NAME_1, 0)) .thenThrow(new NameNotFoundException()); // THEN an update is required assertTrue(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 0, mockContext)); } public void testPackageRequiresUpdate() throws Exception { // GIVEN a package that is installed on the device PackageInfo pi = new PackageInfo(); pi.packageName = TEST_PACKAGE_NAME_1; pi.versionCode = 1; when(mockPackageManager.getPackageInfo(TEST_PACKAGE_NAME_1, 0)).thenReturn(pi); // WHEN checking whether an update is required // THEN verify that update required returns the correct result depending on the minimum // version code requested. assertFalse(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 0, mockContext)); assertFalse(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 1, mockContext)); assertTrue(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME_1, 2, mockContext)); } public void testIsConnectedToNetwork() throws Exception { // GIVEN the device is currently connected to mobile network setCurrentNetworkMock(ConnectivityManager.TYPE_MOBILE, true); // WHEN checking connectivity // THEN utils should return true assertTrue(mUtils.isConnectedToNetwork(mockContext)); // GIVEN the device is currently connected to wifi setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, true); // WHEN checking connectivity // THEN utils should return true assertTrue(mUtils.isConnectedToNetwork(mockContext)); // GIVEN the device is currently disconnected on wifi setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, false); // WHEN checking connectivity // THEN utils should return false assertFalse(mUtils.isConnectedToNetwork(mockContext)); } public void testIsConnectedToWifi() throws Exception { // GIVEN the device is currently connected to mobile network setCurrentNetworkMock(ConnectivityManager.TYPE_MOBILE, true); // WHEN checking whether connected to wifi // THEN utils should return false assertFalse(mUtils.isNetworkTypeConnected(mockContext, ConnectivityManager.TYPE_WIFI)); // GIVEN the device is currently connected to wifi setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, true); // WHEN checking whether connected to wifi // THEN utils should return true assertTrue(mUtils.isNetworkTypeConnected(mockContext, ConnectivityManager.TYPE_WIFI)); // GIVEN the device is currently disconnected on wifi setCurrentNetworkMock(ConnectivityManager.TYPE_WIFI, false); // WHEN checking whether connected to wifi // THEN utils should return false assertFalse(mUtils.isNetworkTypeConnected(mockContext, ConnectivityManager.TYPE_WIFI)); } public void testIsConnectedToEthernet() throws Exception { // GIVEN the device is currently connected to mobile network setCurrentNetworkMock(ConnectivityManager.TYPE_MOBILE, true); // WHEN checking whether connected to wifi // THEN utils should return false assertFalse(mUtils.isNetworkTypeConnected(mockContext, ConnectivityManager.TYPE_ETHERNET)); // GIVEN the device is currently connected to wifi setCurrentNetworkMock(ConnectivityManager.TYPE_ETHERNET, true); // WHEN checking whether connected to wifi // THEN utils should return true assertTrue(mUtils.isNetworkTypeConnected(mockContext, ConnectivityManager.TYPE_ETHERNET)); // GIVEN the device is currently disconnected on wifi setCurrentNetworkMock(ConnectivityManager.TYPE_ETHERNET, false); // WHEN checking whether connected to wifi // THEN utils should return false assertFalse(mUtils.isNetworkTypeConnected(mockContext, ConnectivityManager.TYPE_ETHERNET)); } public void testGetActiveNetworkInfo() throws Exception { // GIVEN the device is connected to a network. final NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, null, null); when(mockConnectivityManager.getActiveNetworkInfo()).thenReturn(networkInfo); // THEN calling getActiveNetworkInfo should return the correct network info. assertEquals(mUtils.getActiveNetworkInfo(mockContext), networkInfo); } public void testCurrentLauncherSupportsManagedProfiles_noLauncherSet() throws Exception { // GIVEN there currently is no default launcher set when(mockPackageManager.resolveActivity(any(Intent.class), anyInt())) .thenReturn(null); // WHEN checking whether the current launcher support managed profiles // THEN utils should return false assertFalse(mUtils.currentLauncherSupportsManagedProfiles(mockContext)); } public void testCurrentLauncherSupportsManagedProfiles() throws Exception { // GIVEN the current default launcher is built against lollipop setLauncherMock(Build.VERSION_CODES.LOLLIPOP); // WHEN checking whether the current launcher support managed profiles // THEN utils should return true assertTrue(mUtils.currentLauncherSupportsManagedProfiles(mockContext)); // GIVEN the current default launcher is built against kitkat setLauncherMock(Build.VERSION_CODES.KITKAT); // WHEN checking whether the current launcher support managed profiles // THEN utils should return false assertFalse(mUtils.currentLauncherSupportsManagedProfiles(mockContext)); } public void testFindDeviceAdmin_ComponentName() throws Exception { // GIVEN a package info with more than one device admin setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME, TEST_DEVICE_ADMIN_NAME_2); // THEN calling findDeviceAdmin returns the correct admin assertEquals(TEST_COMPONENT_NAME_2, mUtils.findDeviceAdmin(null, TEST_COMPONENT_NAME_2, mockContext, TEST_USER_ID)); } public void testFindDeviceAdmin_PackageName() throws Exception { // GIVEN a package info with one device admin setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME); // THEN calling findDeviceAdmin returns the correct admin assertEquals(TEST_COMPONENT_NAME, mUtils.findDeviceAdmin( TEST_PACKAGE_NAME_1, null, mockContext, TEST_USER_ID)); } public void testFindDeviceAdmin_NoPackageName() throws Exception { // GIVEN no package info file when(mockPackageManager.getPackageInfoAsUser(TEST_PACKAGE_NAME_1, PackageManager.GET_RECEIVERS | PackageManager.MATCH_DISABLED_COMPONENTS, TEST_USER_ID)) .thenReturn(null); // THEN throw IllegalProvisioningArgumentException try { mUtils.findDeviceAdmin( TEST_PACKAGE_NAME_1, null, mockContext, TEST_USER_ID); fail(); } catch (IllegalProvisioningArgumentException e) { // expected } } public void testFindDeviceAdmin_AnotherComponentName() throws Exception { // GIVEN a package info with one device admin setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME); // THEN looking another device admin throws IllegalProvisioningArgumentException try { mUtils.findDeviceAdmin( null, TEST_COMPONENT_NAME_2, mockContext, TEST_USER_ID); fail(); } catch (IllegalProvisioningArgumentException e) { // expected } } public void testFindDeviceAdminInPackageInfo_Success() throws Exception { // GIVEN a package info with one device admin PackageInfo packageInfo = setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME); // THEN calling findDeviceAdminInPackageInfo returns the correct admin assertEquals(TEST_COMPONENT_NAME, mUtils.findDeviceAdminInPackageInfo(TEST_PACKAGE_NAME_1, null, packageInfo)); } public void testFindDeviceAdminInPackageInfo_PackageNameMismatch() throws Exception { // GIVEN a package info with one device admin PackageInfo packageInfo = setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME); // THEN calling findDeviceAdminInPackageInfo with the wrong package name return null assertNull(mUtils.findDeviceAdminInPackageInfo(TEST_PACKAGE_NAME_2, null, packageInfo)); } public void testFindDeviceAdminInPackageInfo_NoAdmin() throws Exception { // GIVEN a package info with no device admin PackageInfo packageInfo = setUpPackage(TEST_PACKAGE_NAME_1); // THEN calling findDeviceAdminInPackageInfo returns null assertNull(mUtils.findDeviceAdminInPackageInfo(TEST_PACKAGE_NAME_1, null, packageInfo)); } public void testFindDeviceAdminInPackageInfo_TwoAdmins() throws Exception { // GIVEN a package info with more than one device admin PackageInfo packageInfo = setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME, TEST_DEVICE_ADMIN_NAME_2); // THEN calling findDeviceAdminInPackageInfo returns null assertNull(mUtils.findDeviceAdminInPackageInfo(TEST_PACKAGE_NAME_1, null, packageInfo)); } public void testFindDeviceAdminInPackageInfo_TwoAdminsWithComponentName() throws Exception { // GIVEN a package info with more than one device admin PackageInfo packageInfo = setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME, TEST_DEVICE_ADMIN_NAME_2); // THEN calling findDeviceAdminInPackageInfo return component 1 assertEquals(TEST_COMPONENT_NAME, mUtils.findDeviceAdminInPackageInfo( TEST_PACKAGE_NAME_1, TEST_COMPONENT_NAME, packageInfo)); } public void testFindDeviceAdminInPackageInfo_InvalidComponentName() throws Exception { // GIVEN a package info with component 1 PackageInfo packageInfo = setUpPackage(TEST_PACKAGE_NAME_1, TEST_DEVICE_ADMIN_NAME); // THEN calling findDeviceAdminInPackageInfo with component 2 returns null assertNull(mUtils.findDeviceAdminInPackageInfo( TEST_PACKAGE_NAME_1, TEST_COMPONENT_NAME_2, packageInfo)); } public void testComputeHashOfByteArray() { // GIVEN a byte array byte[] bytes = "TESTARRAY".getBytes(); // GIVEN its Sha256 hash byte[] sha256 = new byte[] {100, -45, -118, -68, -104, -15, 63, -60, -84, -44, -13, -63, 53, -50, 104, -63, 38, 122, 16, -44, -85, -50, 67, 98, 78, 121, 11, 72, 79, 40, 107, 125}; // THEN computeHashOfByteArray returns the correct result assertTrue(Arrays.equals(sha256, mUtils.computeHashOfByteArray(bytes))); } public void testComputeHashOfFile() { // GIVEN a file with test data final String fileLocation = getContext().getFilesDir().toString() + "/" + TEST_FILE_NAME; String string = "Hello world!"; FileOutputStream outputStream; try { outputStream = getContext().openFileOutput(TEST_FILE_NAME, Context.MODE_PRIVATE); outputStream.write(string.getBytes()); outputStream.close(); } catch (Exception e) { e.printStackTrace(); } // GIVEN the file's Sha256 hash byte[] sha256 = new byte[] {-64, 83, 94, 75, -30, -73, -97, -3, -109, 41, 19, 5, 67, 107, -8, -119, 49, 78, 74, 63, -82, -64, 94, -49, -4, -69, 125, -13, 26, -39, -27, 26}; //THEN the Sha256 hash is correct assertTrue( Arrays.equals(sha256, mUtils.computeHashOfFile(fileLocation, Utils.SHA256_TYPE))); } public void testComputeHashOfFile_NotPresent() { // GIVEN no file is present final String fileLocation = getContext().getFilesDir().toString() + "/" + TEST_FILE_NAME; getContext().deleteFile(TEST_FILE_NAME); // THEN computeHashOfFile should return null assertNull(mUtils.computeHashOfFile(fileLocation, Utils.SHA256_TYPE)); } public void testCanResolveIntentAsUser() { // GIVEN intent is null // THEN intent should not be resolved assertFalse(mUtils.canResolveIntentAsUser(mockContext, null, TEST_USER_ID)); // GIVEN a valid intent Intent intent = new Intent(); // WHEN resolve activity as user returns null when(mockPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(null); // THEN intent should not be resolved for user assertFalse(mUtils.canResolveIntentAsUser(mockContext, intent, TEST_USER_ID)); // WHEN resolve activity as user returns valid resolve info when(mockPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(new ResolveInfo()); // THEN intent should be resolved assertTrue(mUtils.canResolveIntentAsUser(mockContext, intent, TEST_USER_ID)); } private ApplicationInfo createApplicationInfo( String packageName, boolean system, boolean hiddenUntilInstalled) { ApplicationInfo ai = new ApplicationInfo(); ai.packageName = packageName; if (system) { ai.flags = ApplicationInfo.FLAG_SYSTEM; } ai.hiddenUntilInstalled = hiddenUntilInstalled; return ai; } private void setCurrentNetworkMock(int type, boolean connected) { NetworkInfo networkInfo = new NetworkInfo(type, 0, null, null); networkInfo.setDetailedState( connected ? NetworkInfo.DetailedState.CONNECTED : NetworkInfo.DetailedState.DISCONNECTED, null, null); when(mockConnectivityManager.getActiveNetworkInfo()).thenReturn(networkInfo); } private void setLauncherMock(int targetSdkVersion) throws Exception { ApplicationInfo appInfo = new ApplicationInfo(); appInfo.targetSdkVersion = targetSdkVersion; ActivityInfo actInfo = new ActivityInfo(); actInfo.packageName = TEST_PACKAGE_NAME_1; ResolveInfo resInfo = new ResolveInfo(); resInfo.activityInfo = actInfo; when(mockPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(resInfo); when(mockPackageManager.getApplicationInfo(TEST_PACKAGE_NAME_1, 0)).thenReturn(appInfo); } private PackageInfo setUpPackage(String packageName, String... adminNames) throws NameNotFoundException { PackageInfo packageInfo = new PackageInfo(); packageInfo.packageName = packageName; packageInfo.receivers = new ActivityInfo[adminNames.length]; for (int i = 0; i < adminNames.length; i++) { ActivityInfo receiver = new ActivityInfo(); receiver.permission = android.Manifest.permission.BIND_DEVICE_ADMIN; receiver.name = adminNames[i]; packageInfo.receivers[i] = receiver; } when(mockPackageManager.getPackageInfoAsUser(packageName, PackageManager.GET_RECEIVERS | PackageManager.MATCH_DISABLED_COMPONENTS, TEST_USER_ID)) .thenReturn(packageInfo); return packageInfo; } }