Make DPM/DPMS unit-testable

- Now all services that DPMS uses are injectable.
- Introduce some wrappers to make static methods and final class mockable.
(e.g. for Binder.getCallingUid())

- In unit tests we replace those with Mockito mocks, except we use a partial
mock for PackageManager, because we use way too many methods of this and
most of them are okay to use directly.

- To install a partial mock to PackageManager, I needed to make
ApplicationPackageManager @hide public non-final.

- For a starter, added tests for DPM.setAmin().

Bug 24061108

Change-Id: I2afd51d8bc0038992d5f9be38c686260be775b75
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
new file mode 100644
index 0000000..7cce56c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 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.server.devicepolicy;
+
+import com.android.server.LocalServices;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link DevicePolicyManager} and {@link DevicePolicyManagerService}.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+ (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
+ */
+public class DevicePolicyManagerTest extends DpmTestBase {
+
+    private DpmMockContext mContext;
+    public DevicePolicyManager dpm;
+    public DevicePolicyManagerServiceTestable dpms;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = getContext();
+
+        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
+                .thenReturn(true);
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+        dpm = new DevicePolicyManagerTestable(mContext, dpms);
+    }
+
+    public void testHasNoFeature() {
+        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
+                .thenReturn(false);
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+        // If the device has no DPMS feature, it shouldn't register the local service.
+        assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
+    }
+
+    /**
+     * Caller doesn't have proper permissions.
+     */
+    public void testSetActiveAdmin_SecurityException() {
+        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
+
+        // 1. Failure cases.
+
+        // Caller doesn't have MANAGE_DEVICE_ADMINS.
+        try {
+            dpm.setActiveAdmin(admin, false);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+
+        // Caller has MANAGE_DEVICE_ADMINS, but for different user.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+        try {
+            dpm.setActiveAdmin(admin, false, DpmMockContext.CALLER_USER_HANDLE + 1);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testSetActiveAdmin() {
+        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
+
+        // 1. Prepare mock package manager (and other mocks)
+
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Create ResolveInfo for the admin.
+        final Intent resolveIntent = new Intent();
+        resolveIntent.setComponent(admin);
+        final List<ResolveInfo> realResolveInfo =
+                mRealTestContext.getPackageManager().queryBroadcastReceivers(
+                        resolveIntent,
+                        PackageManager.GET_META_DATA
+                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+        assertNotNull(realResolveInfo);
+        assertEquals(1, realResolveInfo.size());
+
+        // We need to rewrite the UID in the activity info.
+        realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
+
+        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
+                any(Intent.class), // TODO check the intent too.
+                eq(PackageManager.GET_META_DATA
+                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(DpmMockContext.CALLER_USER_HANDLE)
+        );
+
+        // 2. Everything is ready; call the method.
+        dpm.setActiveAdmin(admin, false);
+
+        // 3. Verify internal calls.
+
+        // Check if the boradcast is sent.
+        final ArgumentCaptor<Intent> intentCap = ArgumentCaptor.forClass(Intent.class);
+        final ArgumentCaptor<UserHandle> uhCap = ArgumentCaptor.forClass(UserHandle.class);
+
+        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+                intentCap.capture(),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // First call from saveSettingsLocked().
+        assertEquals(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED,
+                intentCap.getAllValues().get(0).getAction());
+
+        // Second call from setActiveAdmin/sendAdminCommandLocked()
+        assertEquals(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+                intentCap.getAllValues().get(1).getAction());
+
+        // TODO Verify other calls too.
+    }
+}
+