CTS: Create test for DISALLOW_INSTALL_UNKNOWN_SOURCES
Added a new CTS app - PackageInstaller to test installing apk in a non
device owner package under policy restrictions
Note:
UserRestrictionActivity is copied from ManagedProfileTest
Bug: 18928535
Change-Id: I4fced5b345c4594009203681501ad84079dd3c61
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index cf7da2f..41f9dc3 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -100,6 +100,7 @@
CtsManagedProfileApp \
CtsMonkeyApp \
CtsMonkeyApp2 \
+ CtsPackageInstallerApp \
CtsPermissionApp \
CtsSimpleApp \
CtsSimplePreMApp \
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
index 6e520c3..fe07bcb 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
@@ -71,6 +71,13 @@
android:resource="@xml/authenticator" />
</service>
+ <activity android:name=".UserRestrictionActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java
new file mode 100644
index 0000000..fed1a79
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java
@@ -0,0 +1,81 @@
+/*
+ * 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.cts.deviceandprofileowner;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
+import android.util.Log;
+
+/**
+ * Simple activity that adds or clears a user restriction depending on the value of the extras.
+ */
+public class UserRestrictionActivity extends Activity {
+
+ private static final String TAG = UserRestrictionActivity.class.getName();
+
+ private static final String EXTRA_RESTRICTION_KEY = "extra-restriction-key";
+ private static final String EXTRA_COMMAND = "extra-command";
+
+ private static final String ADD_COMMAND = "add-restriction";
+ private static final String CLEAR_COMMAND = "clear-restriction";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ handleIntent(getIntent());
+ }
+
+ // Overriding this method in case another intent is sent to this activity before finish()
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleIntent(intent);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // Calling finish() here because doing it in onCreate(), onStart() or onResume() makes
+ // "adb shell am start" timeout if using the -W option.
+ finish();
+ }
+
+ private void handleIntent(Intent intent) {
+ DevicePolicyManager dpm = (DevicePolicyManager)
+ getSystemService(Context.DEVICE_POLICY_SERVICE);
+ String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
+ String command = intent.getStringExtra(EXTRA_COMMAND);
+ Log.i(TAG, "Command: \"" + command + "\". Restriction: \"" + restrictionKey + "\"");
+
+ if (ADD_COMMAND.equals(command)) {
+ dpm.addUserRestriction(BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+ Log.i(TAG, "Added user restriction " + restrictionKey
+ + " for user " + Process.myUserHandle());
+ } else if (CLEAR_COMMAND.equals(command)) {
+ dpm.clearUserRestriction(
+ BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+ Log.i(TAG, "Cleared user restriction " + restrictionKey
+ + " for user " + Process.myUserHandle());
+ } else {
+ Log.e(TAG, "Invalid command: " + command);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
new file mode 100644
index 0000000..e68c884
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
@@ -0,0 +1,33 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsPackageInstallerApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner ub-uiautomator
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml b/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml
new file mode 100644
index 0000000..aaa88f2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.packageinstaller">
+
+ <uses-sdk android:minSdkVersion="21"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <receiver
+ android:name=".ClearDeviceOwnerTest$BasicAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.packageinstaller"
+ android:label="Package Installer CTS Tests" />
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml
new file mode 100644
index 0000000..de4a9e1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml
@@ -0,0 +1,3 @@
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+ <uses-policies />
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
similarity index 70%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
rename to hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
index 0eddbee..f994e9e 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
@@ -13,17 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.deviceowner;
+package com.android.cts.packageinstaller;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+
+import com.android.cts.packageinstaller.ClearDeviceOwnerTest.BasicAdminReceiver;
import java.io.File;
import java.io.FileInputStream;
@@ -31,34 +37,41 @@
import java.io.OutputStream;
/**
- * This class tests silent package install and uninstall by a device owner.
+ * Base test case for testing PackageInstaller.
*/
-public class PackageInstallTest extends BaseDeviceOwnerTest {
- private static final String TEST_APP_LOCATION = "/data/local/tmp/CtsSimpleApp.apk";
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
- private static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
+public class BasePackageInstallTest extends InstrumentationTestCase {
+ protected static final String TEST_APP_LOCATION = "/data/local/tmp/CtsSimpleApp.apk";
+ protected static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+ protected static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
private static final String ACTION_INSTALL_COMMIT =
"com.android.cts.deviceowner.INTENT_PACKAGE_INSTALL_COMMIT";
- private static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
+ protected static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
+ public static final String PACKAGE_NAME = SilentPackageInstallTest.class.getPackage().getName();
+ protected Context mContext;
+ protected UiDevice mDevice;
+ protected DevicePolicyManager mDevicePolicyManager;
private PackageManager mPackageManager;
private PackageInstaller mPackageInstaller;
private PackageInstaller.Session mSession;
- private boolean mCallbackReceived;
- private int mCallbackStatus;
+ protected boolean mCallbackReceived;
+ protected int mCallbackStatus;
+ protected Intent mCallbackIntent;
- private final Object mPackageInstallerTimeoutLock = new Object();
+ protected final Object mPackageInstallerTimeoutLock = new Object();
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mContext.unregisterReceiver(this);
synchronized (mPackageInstallerTimeoutLock) {
mCallbackStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PACKAGE_INSTALLER_STATUS_UNDEFINED);
if (mCallbackStatus == PackageInstaller.STATUS_SUCCESS) {
+ mContext.unregisterReceiver(this);
assertEquals(TEST_APP_PKG, intent.getStringExtra(
PackageInstaller.EXTRA_PACKAGE_NAME));
+ } else if (mCallbackStatus == PackageInstaller.STATUS_PENDING_USER_ACTION) {
+ mCallbackIntent = (Intent) intent.getExtras().get(Intent.EXTRA_INTENT);
}
mCallbackReceived = true;
mPackageInstallerTimeoutLock.notify();
@@ -69,6 +82,10 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ mContext = getInstrumentation().getContext();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mDevicePolicyManager = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
mPackageManager = mContext.getPackageManager();
mPackageInstaller = mPackageManager.getPackageInstaller();
assertNotNull(mPackageInstaller);
@@ -79,7 +96,10 @@
@Override
protected void tearDown() throws Exception {
- mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+ if (mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME) ||
+ mDevicePolicyManager.isProfileOwnerApp(PACKAGE_NAME)) {
+ mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+ }
try {
mContext.unregisterReceiver(mBroadcastReceiver);
} catch (IllegalArgumentException e) {
@@ -91,33 +111,12 @@
super.tearDown();
}
- public void testSilentInstallUninstall() throws Exception {
- // install the app
- assertInstallPackage();
-
- // uninstall the app again
- assertTrue(tryUninstallPackage());
- assertFalse(isPackageInstalled(TEST_APP_PKG));
+ protected static ComponentName getWho() {
+ return new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
}
- public void testUninstallBlocked() throws Exception {
- // install the app
- assertInstallPackage();
-
- mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, true);
- assertTrue(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
- assertTrue(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
- assertFalse(tryUninstallPackage());
- assertTrue(isPackageInstalled(TEST_APP_PKG));
-
- mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
- assertFalse(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
- assertFalse(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
- assertTrue(tryUninstallPackage());
+ protected void assertInstallPackage() throws Exception {
assertFalse(isPackageInstalled(TEST_APP_PKG));
- }
-
- private void assertInstallPackage() throws Exception {
synchronized (mPackageInstallerTimeoutLock) {
mCallbackReceived = false;
mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
@@ -134,7 +133,7 @@
assertTrue(isPackageInstalled(TEST_APP_PKG));
}
- private boolean tryUninstallPackage() throws Exception {
+ protected boolean tryUninstallPackage() throws Exception {
assertTrue(isPackageInstalled(TEST_APP_PKG));
synchronized (mPackageInstallerTimeoutLock) {
mCallbackReceived = false;
@@ -151,7 +150,7 @@
}
}
- private void installPackage(String packageLocation) throws Exception {
+ protected void installPackage(String packageLocation) throws Exception {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = mPackageInstaller.createSession(params);
@@ -184,11 +183,11 @@
mContext,
sessionId,
broadcastIntent,
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent.getIntentSender();
}
- private boolean isPackageInstalled(String packageName) {
+ protected boolean isPackageInstalled(String packageName) {
try {
PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
return pi != null;
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java
new file mode 100644
index 0000000..a06271b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.cts.packageinstaller;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Base class for profile and device based tests.
+ *
+ * This class handles making sure that the test is the profile or device owner and that it has an
+ * active admin registered, so that all tests may assume these are done.
+ */
+public class ClearDeviceOwnerTest extends InstrumentationTestCase {
+
+ public static class BasicAdminReceiver extends DeviceAdminReceiver {
+ }
+
+ public static final String PACKAGE_NAME = BasicAdminReceiver.class.getPackage().getName();
+ public static final ComponentName ADMIN_RECEIVER_COMPONENT = new ComponentName(
+ PACKAGE_NAME, BasicAdminReceiver.class.getName());
+
+ private DevicePolicyManager mDevicePolicyManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mDevicePolicyManager = (DevicePolicyManager)
+ getInstrumentation().getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
+ assertNotNull(mDevicePolicyManager);
+
+ assertTrue(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+ assertTrue("App is not device owner", mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ removeActiveAdmin(ADMIN_RECEIVER_COMPONENT);
+ mDevicePolicyManager.clearDeviceOwnerApp(PACKAGE_NAME);
+ assertFalse(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+ assertFalse(mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+
+ super.tearDown();
+ }
+
+ // This test clears the device owner and active admin on tearDown(). To be called from the host
+ // side test once a test case is finished.
+ public void testClearDeviceOwner() {
+ }
+
+ private void removeActiveAdmin(ComponentName cn) throws InterruptedException {
+ if (mDevicePolicyManager.isAdminActive(cn)) {
+ mDevicePolicyManager.removeActiveAdmin(cn);
+ for (int i = 0; i < 1000 && mDevicePolicyManager.isAdminActive(cn); i++) {
+ Thread.sleep(100);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
new file mode 100644
index 0000000..96affae
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.cts.packageinstaller;
+
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+/**
+ * This class tests manual package install and uninstall by a device owner.
+ */
+public class ManualPackageInstallTest extends BasePackageInstallTest {
+ private static final int AUTOMATOR_WAIT_TIMEOUT = 5000;
+ private static final int INSTALL_WAIT_TIME = 5000;
+
+ private static final BySelector POPUP_BUTTON_SELECTOR = By
+ .clazz(android.widget.Button.class.getName())
+ .res("android:id/button1")
+ .pkg("com.google.android.packageinstaller");
+ private static final BySelector POPUP_TEXT_SELECTOR = By
+ .clazz(android.widget.TextView.class.getName())
+ .res("android:id/alertTitle")
+ .pkg("com.google.android.packageinstaller");
+ private static final BySelector INSTALL_BUTTON_SELECTOR = By
+ .clazz(android.widget.Button.class.getName())
+ .res("com.android.packageinstaller:id/ok_button")
+ .pkg("com.google.android.packageinstaller");
+
+ public void testManualInstallSucceeded() throws Exception {
+ assertInstallPackage();
+ }
+
+ public void testManualInstallBlocked() throws Exception {
+ synchronized (mPackageInstallerTimeoutLock) {
+ mCallbackReceived = false;
+ mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
+ }
+ // Calls the original installPackage which does not click through the install button.
+ super.installPackage(TEST_APP_LOCATION);
+ synchronized (mPackageInstallerTimeoutLock) {
+ try {
+ mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ }
+ assertTrue(mCallbackReceived);
+ assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
+ }
+
+ mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(mCallbackIntent);
+
+ automateDismissInstallBlockedDialog();
+
+ // Assuming installation is not synchronous, we should wait a while before checking.
+ Thread.sleep(INSTALL_WAIT_TIME);
+ assertFalse(isPackageInstalled(TEST_APP_PKG));
+ }
+
+ @Override
+ protected void installPackage(String packageLocation) throws Exception {
+ super.installPackage(packageLocation);
+
+ synchronized (mPackageInstallerTimeoutLock) {
+ try {
+ mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ }
+ assertTrue(mCallbackReceived);
+ assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
+ }
+
+ // Use a receiver to listen for package install.
+ synchronized (mPackageInstallerTimeoutLock) {
+ mCallbackReceived = false;
+ mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
+ }
+
+ mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(mCallbackIntent);
+
+ automateInstallClick();
+ }
+
+ private void automateInstallClick() {
+ mDevice.wait(Until.hasObject(INSTALL_BUTTON_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+ UiObject2 button = mDevice.findObject(INSTALL_BUTTON_SELECTOR);
+ assertNotNull("Install button not found", button);
+ button.click();
+ }
+
+ private void automateDismissInstallBlockedDialog() {
+ mDevice.wait(Until.hasObject(POPUP_TEXT_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+ UiObject2 text = mDevice.findObject(POPUP_TEXT_SELECTOR);
+ assertNotNull("Alert dialog not found", text);
+ // "OK" button only present in the dialog if it is blocked by policy.
+ UiObject2 button = mDevice.findObject(POPUP_BUTTON_SELECTOR);
+ assertNotNull("OK button not found", button);
+ button.click();
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java
new file mode 100644
index 0000000..f1a80b9
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.cts.packageinstaller;
+
+/**
+ * This class tests silent package install and uninstall by a device owner.
+ */
+public class SilentPackageInstallTest extends BasePackageInstallTest {
+ public void testSilentInstallUninstall() throws Exception {
+ // install the app
+ assertInstallPackage();
+
+ // uninstall the app again
+ assertTrue(tryUninstallPackage());
+ assertFalse(isPackageInstalled(TEST_APP_PKG));
+ }
+
+ public void testUninstallBlocked() throws Exception {
+ // install the app
+ assertInstallPackage();
+
+ mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, true);
+ assertTrue(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
+ assertTrue(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
+ assertFalse(tryUninstallPackage());
+ assertTrue(isPackageInstalled(TEST_APP_PKG));
+
+ mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+ assertFalse(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
+ assertFalse(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
+ assertTrue(tryUninstallPackage());
+ assertFalse(isPackageInstalled(TEST_APP_PKG));
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 650e963..4fc14e4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -17,7 +17,6 @@
package com.android.cts.devicepolicy;
import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.InstrumentationResultParser;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -363,4 +362,20 @@
CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
return commandOutput.startsWith("Success:");
}
+
+ protected String getSettings(String namespace, String name, int userId)
+ throws DeviceNotAvailableException {
+ String command = "settings --user " + userId + " get " + namespace + " " + name;
+ String commandOutput = getDevice().executeShellCommand(command);
+ CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+ return commandOutput.replace("\n", "").replace("\r", "");
+ }
+
+ protected void putSettings(String namespace, String name, String value, int userId)
+ throws DeviceNotAvailableException {
+ String command = "settings --user " + userId + " put " + namespace + " " + name
+ + " " + value;
+ String commandOutput = getDevice().executeShellCommand(command);
+ CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 7cb8f3b..8d22638 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,9 +16,7 @@
package com.android.cts.devicepolicy;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
+import java.io.File;
import java.lang.Exception;
/**
@@ -49,6 +47,18 @@
private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
+ private static final String TEST_APP_APK = "CtsSimpleApp.apk";
+ private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+ private static final String TEST_APP_LOCATION = "/data/local/tmp/";
+
+ private static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
+ private static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
+ private static final String PACKAGE_INSTALLER_ADMIN_COMPONENT =
+ PACKAGE_INSTALLER_PKG + "/" + ".ClearDeviceOwnerTest$BasicAdminReceiver";
+ private static final String PACKAGE_INSTALLER_CLEAR_DEVICE_OWNER_TEST_CLASS =
+ PACKAGE_INSTALLER_PKG + ".ClearDeviceOwnerTest";
+
+ @Override
public void tearDown() throws Exception {
if (mHasFeature) {
getDevice().uninstallPackage(DEVICE_OWNER_PKG);
@@ -117,4 +127,28 @@
"testRemoveAccounts", 0));
}
}
+
+ public void testSilentPackageInstall() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+ try {
+ // Install the test and prepare the test apk.
+ installApp(PACKAGE_INSTALLER_APK);
+ assertTrue(setDeviceOwner(PACKAGE_INSTALLER_ADMIN_COMPONENT));
+
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
+ assertTrue(runDeviceTests(PACKAGE_INSTALLER_PKG,
+ PACKAGE_INSTALLER_PKG + ".SilentPackageInstallTest"));
+ } finally {
+ assertTrue("Failed to remove device owner.", runDeviceTests(PACKAGE_INSTALLER_PKG,
+ PACKAGE_INSTALLER_CLEAR_DEVICE_OWNER_TEST_CLASS));
+ String command = "rm " + TEST_APP_LOCATION + apk.getName();
+ String commandOutput = getDevice().executeShellCommand(command);
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ getDevice().uninstallPackage(PACKAGE_INSTALLER_PKG);
+ }
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 439c85f..43e6730 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -20,6 +20,8 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
+import java.io.File;
+
/**
* Set of tests for usecases that apply to profile and device owner.
* This class is the base class of MixedProfileOwnerTest and MixedDeviceOwnerTest and is abstract
@@ -41,8 +43,18 @@
private static final String CERT_INSTALLER_PKG = "com.android.cts.certinstaller";
private static final String CERT_INSTALLER_APK = "CtsCertInstallerApp.apk";
+ private static final String TEST_APP_APK = "CtsSimpleApp.apk";
+ private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+ private static final String TEST_APP_LOCATION = "/data/local/tmp/";
+
+ private static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
+ private static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
+
protected static final int USER_OWNER = 0;
+ private static final String ADD_RESTRICTION_COMMAND = "add-restriction";
+ private static final String CLEAR_RESTRICTION_COMMAND = "clear-restriction";
+
// ID of the user all tests are run as. For device owner this will be 0, for profile owner it
// is the user id of the created profile.
protected int mUserId;
@@ -167,7 +179,6 @@
executeDeviceTestClass(".ApplicationHiddenTest");
}
- // TODO: Remove AccountManagementTest from XTS after GTS is released for MNC.
public void testAccountManagement() throws Exception {
if (!mHasFeature) {
return;
@@ -206,6 +217,49 @@
}
}
+ public void testPackageInstallUserRestrictions() throws Exception {
+ // UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES
+ final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
+ final String UNKNOWN_SOURCES_SETTING = "install_non_market_apps";
+ final String SECURE_SETTING_CATEGORY = "secure";
+ final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+ String unknownSourceSetting = null;
+ try {
+ // Install the test and prepare the test apk.
+ installApp(PACKAGE_INSTALLER_APK);
+ assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
+
+ // Add restrictions and test if we can install the apk.
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ ADD_RESTRICTION_COMMAND, mUserId);
+ assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+ "testManualInstallBlocked", mUserId));
+
+ // Clear restrictions and test if we can install the apk.
+ changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ CLEAR_RESTRICTION_COMMAND, mUserId);
+
+ // Enable Unknown sources in Settings.
+ unknownSourceSetting =
+ getSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, mUserId);
+ putSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, "1", mUserId);
+ assertEquals("1",
+ getSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, mUserId));
+ assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+ "testManualInstallSucceeded", mUserId));
+ } finally {
+ String command = "rm " + TEST_APP_LOCATION + apk.getName();
+ getDevice().executeShellCommand(command);
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ getDevice().uninstallPackage(PACKAGE_INSTALLER_APK);
+ if (unknownSourceSetting != null) {
+ putSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, unknownSourceSetting,
+ mUserId);
+ }
+ }
+ }
+
protected void executeDeviceTestClass(String className) throws Exception {
assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId));
}
@@ -213,4 +267,18 @@
protected void executeDeviceTestMethod(String className, String testName) throws Exception {
assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, testName, mUserId));
}
+
+ private void changeUserRestrictionForUser(String key, String command, int userId)
+ throws DeviceNotAvailableException {
+ String adbCommand = "am start -W --user " + userId
+ + " -c android.intent.category.DEFAULT "
+ + " --es extra-command " + command
+ + " --es extra-restriction-key " + key
+ + " " + DEVICE_ADMIN_PKG + "/.UserRestrictionActivity";
+ String commandOutput = getDevice().executeShellCommand(adbCommand);
+ CLog.logAndDisplay(LogLevel.INFO,
+ "Output for command " + adbCommand + ": " + commandOutput);
+ assertTrue("Command was expected to succeed " + commandOutput,
+ commandOutput.contains("Status: ok"));
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 4f267d1..96ca469 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -16,12 +16,6 @@
package com.android.cts.devicepolicy;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.io.File;
-
/**
* Set of tests for Device Owner use cases.
*/
@@ -35,10 +29,6 @@
private static final String MANAGED_PROFILE_ADMIN =
MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
- private static final String TEST_APP_APK = "CtsSimpleApp.apk";
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
- private static final String TEST_APP_LOCATION = "/data/local/tmp/";
-
private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
@@ -93,19 +83,6 @@
}
}
- public void testPackageInstall() throws Exception {
- final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
- try {
- getDevice().uninstallPackage(TEST_APP_PKG);
- assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
- executeDeviceOwnerTest("PackageInstallTest");
- } finally {
- String command = "rm " + TEST_APP_LOCATION + apk.getName();
- String commandOutput = getDevice().executeShellCommand(command);
- getDevice().uninstallPackage(TEST_APP_PKG);
- }
- }
-
public void testSystemUpdatePolicy() throws Exception {
executeDeviceOwnerTest("SystemUpdatePolicyTest");
}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 29c5035..f8ea45f 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -158,6 +158,14 @@
bug: 17508787
},
{
+ description: "This test should be outside of official CTS suite until it is verified for all Nexus devices",
+ names: [
+ "com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions",
+ "com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions"
+ ],
+ bug: 18928535
+},
+{
description: "Test is not yet properly implemented",
names: [
"android.voicesettings.cts.ZenModeTest#testAll"
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 375b1a0..1df0ddf 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -490,6 +490,10 @@
'com.android.cts.app.os' : [
'com.android.cts.app.os.OsHostTests#testNonExportedActivities',
],
+ 'com.android.cts.devicepolicy' : [
+ 'com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions',
+ 'com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions',
+ ],
'' : []}
def LogGenerateDescription(name):