Merge "MediaCodecTest: don't assume encoder can use input buffers" into lmp-dev
diff --git a/CtsBuild.mk b/CtsBuild.mk
index 12a9047..dbe93c7 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -47,7 +47,7 @@
endef
define cts-get-native-paths
- $(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe))/$(exe))
+ $(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe),,,$(3))/$(exe)$(2))
endef
define cts-get-package-paths
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 518de4b..721b9d4 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -69,6 +69,7 @@
CtsDeviceTaskswitchingControl \
CtsDeviceUi \
CtsIntentReceiverApp \
+ CtsIntentSenderApp \
CtsManagedProfileApp \
CtsMonkeyApp \
CtsMonkeyApp2 \
@@ -121,6 +122,7 @@
CtsGraphicsTestCases \
CtsGraphics2TestCases \
CtsHardwareTestCases \
+ CtsJobSchedulerDeviceTestCases \
CtsJniTestCases \
CtsKeystoreTestCases \
CtsLocationTestCases \
@@ -177,13 +179,16 @@
CtsSecurityHostTestCases \
CtsUsbTests
-# Native test executables that need to have associated test XMLs.
-cts_native_exes := \
+# List of native tests. For 32 bit targets, assumes that there will be
+# one test executable, and it will end in 32. For 64 bit targets, assumes
+# that there will be two executables, one that ends in 32 for the 32
+# bit executable and one that ends in 64 for the 64 bit executable.
+cts_native_tests := \
NativeMediaTest_SL \
NativeMediaTest_XA \
ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
-cts_native_exes += bionic-unit-tests-cts
+cts_native_tests += bionic-unit-tests-cts
endif
cts_ui_tests := \
@@ -207,17 +212,27 @@
# directory of the final CTS distribution.
CTS_TEST_CASES := $(call cts-get-lib-paths,$(cts_host_libraries)) \
$(call cts-get-package-paths,$(cts_test_packages)) \
- $(call cts-get-native-paths,$(cts_native_exes)) \
$(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
$(call cts-get-ui-lib-paths,$(cts_device_jars)) \
$(call cts-get-ui-lib-paths,$(cts_target_junit_tests)) \
$(call cts-get-executable-paths,$(cts_device_executables))
+# NOTE: If compiling on a 64 bit target, TARGET_2ND_ARCH will be non-empty
+# and will cause the function to expand to the secondary arch object
+# directory. If compiling on a 32 bit target, TARGET_2ND_ARCH will be
+# empty and will cause the function to expand to the primary arch object
+# directory.
+CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),32,$(TARGET_2ND_ARCH))
+
+ifeq ($(TARGET_IS_64_BIT),true)
+CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),64)
+endif
+
# All the XMLs that will end up under the repository/testcases
# and that need to be created before making the final CTS distribution.
CTS_TEST_XMLS := $(call cts-get-test-xmls,$(cts_host_libraries)) \
$(call cts-get-test-xmls,$(cts_test_packages)) \
- $(call cts-get-test-xmls,$(cts_native_exes)) \
+ $(call cts-get-test-xmls,$(cts_native_tests)) \
$(call cts-get-test-xmls,$(cts_target_junit_tests)) \
$(call cts-get-test-xmls,$(cts_ui_tests)) \
$(call cts-get-deqp-test-xmls,$(cts_deqp_test_apis))
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 88386ec..34bc230 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -21,6 +21,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_MULTILIB := both
+
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := cts-sensors-tests ctstestrunner
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index bba42ad..fc899b1 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -48,6 +48,7 @@
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -1272,6 +1273,33 @@
</intent-filter>
</receiver>
+ <activity android:name=".jobscheduler.IdleConstraintTestActivity" android:label="@string/js_idle_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_jobscheduler" />
+ </activity>
+
+ <activity android:name=".jobscheduler.ChargingConstraintTestActivity" android:label="@string/js_charging_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_jobscheduler" />
+ </activity>
+
+ <activity android:name=".jobscheduler.ConnectivityConstraintTestActivity" android:label="@string/js_connectivity_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_jobscheduler" />
+ </activity>
+
+ <service android:name=".jobscheduler.MockJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"/>
+
</application>
</manifest>
diff --git a/apps/CtsVerifier/res/layout/js_charging.xml b/apps/CtsVerifier/res/layout/js_charging.xml
new file mode 100644
index 0000000..4c0e552
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_charging.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/js_test_description"
+ android:layout_margin="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/js_padding"
+ android:text="@string/js_charging_description_1"
+ android:textStyle="bold"/>
+ <Button
+ android:id="@+id/js_charging_start_test_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/js_start_test_text"
+ android:onClick="startTest"
+ android:enabled="false"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/charging_off_test_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_charging_off_test"
+ android:textSize="16dp"/>
+ </LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/js_padding"
+ android:text="@string/js_charging_description_2"
+ android:textStyle="bold"/>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/charging_on_test_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_charging_on_test"
+ android:textSize="16dp"/>
+ </LinearLayout>
+ <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_connectivity.xml b/apps/CtsVerifier/res/layout/js_connectivity.xml
new file mode 100644
index 0000000..5208c18
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_connectivity.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/js_test_description"
+ android:layout_margin="@dimen/js_padding"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/js_connectivity_description_1"
+ android:layout_margin="@dimen/js_padding"
+ android:textStyle="bold"/>
+
+ <Button
+ android:id="@+id/js_connectivity_start_test_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/js_start_test_text"
+ android:onClick="startTest"
+ android:enabled="false"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/connectivity_off_test_unmetered_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_unmetered_connectivity_test"
+ android:textSize="16dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/connectivity_off_test_any_connectivity_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_any_connectivity_test"
+ android:textSize="16dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/connectivity_off_test_no_connectivity_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_no_connectivity_test"
+ android:textSize="16dp"/>
+ </LinearLayout>
+
+ <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_idle.xml b/apps/CtsVerifier/res/layout/js_idle.xml
new file mode 100644
index 0000000..90e55ec
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_idle.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/js_test_description"
+ android:layout_margin="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/js_idle_description_1"
+ android:layout_margin="@dimen/js_padding"
+ android:textStyle="bold"/>
+
+ <Button
+ android:id="@+id/js_idle_start_test_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/js_start_test_text"
+ android:onClick="startTest"
+ android:enabled="false"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/idle_off_test_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_idle_item_idle_off"
+ android:textSize="16dp"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/idle_on_test_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_idle_item_idle_on"
+ android:textSize="16dp"/>
+ </LinearLayout>
+ <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pa_main.xml b/apps/CtsVerifier/res/layout/pa_main.xml
index b6b8e4b..76cb7d4 100644
--- a/apps/CtsVerifier/res/layout/pa_main.xml
+++ b/apps/CtsVerifier/res/layout/pa_main.xml
@@ -17,11 +17,15 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
+ <include
+ android:id="@+id/pass_fail_buttons"
+ android:layout_gravity="top"
+ layout="@layout/pass_fail_buttons" />
+
<TextureView
android:id="@+id/texture_view"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <include layout="@layout/pass_fail_buttons" />
+ android:layout_height="match_parent"
+ android:layout_below="@id/pass_fail_buttons" />
</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/dimens.xml b/apps/CtsVerifier/res/values/dimens.xml
index b1367f7..8df5b35 100644
--- a/apps/CtsVerifier/res/values/dimens.xml
+++ b/apps/CtsVerifier/res/values/dimens.xml
@@ -36,4 +36,6 @@
<dimen name="snsr_view_padding_left">8dp</dimen>
<dimen name="snsr_view_padding_right">8dp</dimen>
+ <dimen name="js_padding">10dp</dimen>
+
</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 2a236d1..ffe0121 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -35,6 +35,7 @@
<string name="test_category_streaming">Streaming</string>
<string name="test_category_features">Features</string>
<string name="test_category_deskclock">Clock</string>
+ <string name="test_category_jobscheduler">Job Scheduler</string>
<string name="test_category_other">Other</string>
<string name="clear">Clear</string>
<string name="test_results_cleared">Test results cleared.</string>
@@ -491,6 +492,7 @@
<string name="snsr_setting_auto_rotate_screen_mode">Auto-rotate screen</string>
<string name="snsr_setting_keep_screen_on">Stay awake</string>
<string name="snsr_setting_location_mode">Location</string>
+ <string name="snsr_setting_ambient_display">Ambient Display</string>
<string name="snsr_pass_on_error">Pass Anyway</string>
<string name="snsr_run_automated_tests">The screen will be turned off to execute the tests,
when tests complete, the device will vibrate and the screen will be turned back on.</string>
@@ -1264,4 +1266,28 @@
<string name="device_owner_negative_test">Device owner negative test</string>
<string name="device_owner_negative_test_info">Device owner provisioning should only work on new or factory reset devices. Please click on the "Start provisioning" button and verify that you get a warning dialog telling you that the device is already set up. If that is the case, this test has passed.</string>
<string name="start_device_owner_provisioning_button">Start provisioning</string>
+
+ <!-- Strings for JobScheduler Tests -->
+ <string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
+
+ <string name="js_idle_test">Idle Mode Constraints</string>
+ <string name="js_start_test_text">Start test</string>
+ <string name="js_idle_instructions">Verify the behaviour of the JobScheduler API for when the device is in idle mode. Simply follow the on-screen instructions.</string>
+ <string name="js_idle_description_1">Turn the screen off and then back on in order to begin.</string>
+ <string name="js_idle_item_idle_off">Idle job does not execute when device is not idle.</string>
+ <string name="js_idle_item_idle_on">Idle job does execute when device is forced into idle.</string>
+
+ <string name="js_charging_test">Charging Constraints</string>
+ <string name="js_charging_instructions">Verify the behaviour of the JobScheduler API for when the device is on power and unplugged from power. Simply follow the on-screen instructions.</string>
+ <string name="js_charging_description_1">Unplug the phone in order to begin.</string>
+ <string name="js_charging_off_test">Device not charging will not execute a job with a charging constraint.</string>
+ <string name="js_charging_on_test">Device when charging will execute a job with a charging constraint.</string>
+ <string name="js_charging_description_2">After the above test has passed, plug the device back in to continue. If the above failed, you can simply fail this test.</string>
+
+ <string name="js_connectivity_test">Connectivity Constraints</string>
+ <string name="js_connectivity_instructions">Verify the behaviour of the JobScheduler API for when the device has no access to data connectivity. Simply follow the on-screen instructions.</string>
+ <string name="js_connectivity_description_1">Disable WiFi and Cellular data to begin.</string>
+ <string name="js_unmetered_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
+ <string name="js_any_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
+ <string name="js_no_connectivity_test">Device with no connectivity will still execute a job with no connectivity constraints.</string>
</resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
new file mode 100644
index 0000000..2a94ace
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
@@ -0,0 +1,184 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.cts.verifier.R;
+
+/**
+ * This activity runs the following tests:
+ * - Ask the tester to unplug the phone, and verify that jobs with charging constraints will
+ * not run.
+ * - Ask the tester to ensure the phone is plugged in, and verify that jobs with charging
+ * constraints are run.
+ */
+@TargetApi(21)
+public class ChargingConstraintTestActivity extends ConstraintTestActivity {
+
+ private static final int ON_CHARGING_JOB_ID =
+ ChargingConstraintTestActivity.class.hashCode() + 0;
+ private static final int OFF_CHARGING_JOB_ID =
+ ChargingConstraintTestActivity.class.hashCode() + 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set up the UI.
+ setContentView(R.layout.js_charging);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.js_charging_test, R.string.js_charging_instructions, -1);
+ mStartButton = (Button) findViewById(R.id.js_charging_start_test_button);
+
+ mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+ // Register receiver for connected/disconnected power events.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
+ intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+
+ registerReceiver(mChargingChangedReceiver, intentFilter);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mChargingChangedReceiver);
+ }
+
+ @Override
+ public void startTestImpl() {
+ new TestDeviceUnpluggedConstraint().execute();
+ }
+
+ private BroadcastReceiver mChargingChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
+ mDeviceUnpluggedTestPassed = false;
+ mStartButton.setEnabled(true);
+ } else if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
+ mStartButton.setEnabled(false);
+ if (mDeviceUnpluggedTestPassed) {
+ continueTest();
+ }
+ }
+ }
+ };
+
+ /** Simple state boolean we use to determine whether to continue with the second test. */
+ private boolean mDeviceUnpluggedTestPassed = false;
+
+ /**
+ * After the first test has passed, and preconditions are met, this will kick off the second
+ * test.
+ * See {@link #startTest(android.view.View)}.
+ */
+ private void continueTest() {
+ new TestDevicePluggedInConstraint().execute();
+ }
+
+ /**
+ * Test blocks and can't be run on the main thread.
+ */
+ private void testChargingConstraintFails_notCharging() {
+ mTestEnvironment.setUp();
+
+ mTestEnvironment.setExpectedExecutions(0);
+ JobInfo runOnCharge = new JobInfo.Builder(OFF_CHARGING_JOB_ID, mMockComponent)
+ .setRequiresCharging(true)
+ .build();
+ mJobScheduler.schedule(runOnCharge);
+
+ // Send intent to kick off any jobs. This will be a no-op as the device is not plugged in;
+ // the JobScheduler tracks charging state independently.
+ sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+ boolean testPassed;
+ try {
+ testPassed = mTestEnvironment.awaitTimeout();
+ } catch (InterruptedException e) {
+ testPassed = false;
+ }
+ mDeviceUnpluggedTestPassed = testPassed;
+ runOnUiThread(new ChargingConstraintTestResultRunner(OFF_CHARGING_JOB_ID, testPassed));
+ }
+
+ /**
+ * Test blocks and can't be run on the main thread.
+ */
+ private void testChargingConstraintExecutes_onCharging() {
+ mTestEnvironment.setUp();
+
+ JobInfo delayConstraintAndUnexpiredDeadline =
+ new JobInfo.Builder(ON_CHARGING_JOB_ID, mMockComponent)
+ .setRequiresCharging(true)
+ .build();
+
+ mTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(delayConstraintAndUnexpiredDeadline);
+
+ // Force the JobScheduler to consider any jobs that have charging constraints.
+ sendBroadcast(EXPEDITE_STABLE_CHARGING);
+
+ boolean testPassed;
+ try {
+ testPassed = mTestEnvironment.awaitExecution();
+ } catch (InterruptedException e) {
+ testPassed = false;
+ }
+ runOnUiThread(new ChargingConstraintTestResultRunner(ON_CHARGING_JOB_ID, testPassed));
+ }
+
+ /** Run test for when the <bold>device is not connected to power.</bold>. */
+ private class TestDeviceUnpluggedConstraint extends AsyncTask<Void, Void, Void> {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ testChargingConstraintFails_notCharging();
+
+ // Do not call notifyTestCompleted here, as we're still waiting for the user to put
+ // the device back on charge to continue with TestDevicePluggedInConstraint.
+ return null;
+ }
+ }
+
+ /** Run test for when the <bold>device is connected to power.</bold> */
+ private class TestDevicePluggedInConstraint extends AsyncTask<Void, Void, Void> {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ testChargingConstraintExecutes_onCharging();
+
+ notifyTestCompleted();
+ return null;
+ }
+ }
+
+ private class ChargingConstraintTestResultRunner extends TestResultRunner {
+ ChargingConstraintTestResultRunner(int jobId, boolean testPassed) {
+ super(jobId, testPassed);
+ }
+
+ @Override
+ public void run() {
+ ImageView view;
+ if (mJobId == OFF_CHARGING_JOB_ID) {
+ view = (ImageView) findViewById(R.id.charging_off_test_image);
+ } else if (mJobId == ON_CHARGING_JOB_ID) {
+ view = (ImageView) findViewById(R.id.charging_on_test_image);
+ } else {
+ noteInvalidTest();
+ return;
+ }
+ view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
new file mode 100644
index 0000000..e97539d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
@@ -0,0 +1,184 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.cts.verifier.R;
+
+/**
+ * The majority of the connectivity constraints are done in the device-side test app
+ * android.jobscheduler.cts.deviceside. However a manual tester is required to completely turn off
+ * connectivity on the device in order to verify that jobs with connectivity constraints will not
+ * run in the absence of an internet connection.
+ */
+@TargetApi(21)
+public class ConnectivityConstraintTestActivity extends ConstraintTestActivity {
+ private static final String TAG = "ConnectivityConstraintTestActivity";
+ private static final int ANY_CONNECTIVITY_JOB_ID =
+ ConnectivityConstraintTestActivity.class.hashCode() + 0;
+ private static final int UNMETERED_CONNECTIVITY_JOB_ID =
+ ConnectivityConstraintTestActivity.class.hashCode() + 1;
+ private static final int NO_CONNECTIVITY_JOB_ID =
+ ConnectivityConstraintTestActivity.class.hashCode() + 2;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set up the UI.
+ setContentView(R.layout.js_connectivity);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.js_connectivity_test, R.string.js_connectivity_instructions, -1);
+ mStartButton = (Button) findViewById(R.id.js_connectivity_start_test_button);
+
+ // Disable test start if there is data connectivity.
+ mStartButton.setEnabled(isDataUnavailable());
+ // Register receiver to listen for connectivity changes.
+ IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+ registerReceiver(mConnectivityChangedReceiver, intentFilter);
+
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mConnectivityChangedReceiver);
+ }
+
+ @Override
+ protected void startTestImpl() {
+ new TestConnectivityConstraint().execute();
+ }
+
+ /** Ensure that there's no connectivity before we allow the test to start. */
+ BroadcastReceiver mConnectivityChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "received: " + intent);
+ String extras = "";
+ for (String name : intent.getExtras().keySet()) {
+ extras += " |" + name + " " + intent.getExtras().get(name) + "|";
+
+ }
+ Log.d(TAG, "extras: " + extras);
+ if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ // Only enable the test when we know there is no connectivity.
+ mStartButton.setEnabled(isDataUnavailable());
+ }
+ }
+ };
+
+ private void testUnmeteredConstraintFails_noConnectivity() {
+ testConnectivityConstraintFailsImpl(
+ JobInfo.NETWORK_TYPE_UNMETERED, UNMETERED_CONNECTIVITY_JOB_ID);
+ }
+
+ private void testAnyConnectivityConstraintFails_noConnectivity() {
+ testConnectivityConstraintFailsImpl(JobInfo.NETWORK_TYPE_ANY, ANY_CONNECTIVITY_JOB_ID);
+ }
+
+ private void testNoConnectivityConstraintExecutes_noConnectivity() {
+ JobInfo testJob = new JobInfo.Builder(NO_CONNECTIVITY_JOB_ID, mMockComponent)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
+ .setOverrideDeadline(100000L) // Will not expire.
+ .build();
+
+ mTestEnvironment.setUp();
+ mTestEnvironment.setExpectedExecutions(1);
+
+ mJobScheduler.schedule(testJob);
+
+ // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
+ sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+ boolean testPassed;
+ try {
+ testPassed = mTestEnvironment.awaitExecution();
+ } catch (InterruptedException e) {
+ testPassed = false;
+ }
+ runOnUiThread(
+ new ConnectivityConstraintTestResultRunner(NO_CONNECTIVITY_JOB_ID, testPassed));
+ }
+
+ private void testConnectivityConstraintFailsImpl(int requiredNetworkType, int jobId) {
+ // Use arguments provided to construct job with required connectivity constraint.
+ JobInfo testJob = new JobInfo.Builder(jobId, mMockComponent)
+ .setRequiredNetworkType(requiredNetworkType)
+ .build();
+
+ mTestEnvironment.setUp();
+ mTestEnvironment.setExpectedExecutions(0);
+
+ mJobScheduler.schedule(testJob);
+
+ // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
+ sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+ boolean testPassed;
+ try {
+ testPassed = mTestEnvironment.awaitTimeout();
+ } catch (InterruptedException e) {
+ testPassed = false;
+ }
+ runOnUiThread(
+ new ConnectivityConstraintTestResultRunner(jobId, testPassed));
+ }
+
+ /** Query the active network connection and return if there is no data connection. */
+ private boolean isDataUnavailable() {
+ final ConnectivityManager cm =
+ (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+
+ return (activeNetwork == null) ||
+ !activeNetwork.isConnectedOrConnecting();
+ }
+
+ private class TestConnectivityConstraint extends AsyncTask<Void, Void, Void> {
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+ testUnmeteredConstraintFails_noConnectivity();
+ testAnyConnectivityConstraintFails_noConnectivity();
+ testNoConnectivityConstraintExecutes_noConnectivity();
+
+ notifyTestCompleted();
+ return null;
+ }
+ }
+
+ private class ConnectivityConstraintTestResultRunner extends TestResultRunner {
+ ConnectivityConstraintTestResultRunner(int jobId, boolean testPassed) {
+ super(jobId, testPassed);
+ }
+
+ @Override
+ public void run() {
+ ImageView view;
+ if (mJobId == ANY_CONNECTIVITY_JOB_ID) {
+ view = (ImageView) findViewById(R.id.connectivity_off_test_any_connectivity_image);
+ } else if (mJobId == UNMETERED_CONNECTIVITY_JOB_ID) {
+ view = (ImageView) findViewById(R.id.connectivity_off_test_unmetered_image);
+ } else if (mJobId == NO_CONNECTIVITY_JOB_ID) {
+ view = (ImageView) findViewById(R.id.connectivity_off_test_no_connectivity_image);
+ } else {
+ noteInvalidTest();
+ return;
+ }
+ view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+ }
+ }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
new file mode 100644
index 0000000..da0862a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
@@ -0,0 +1,115 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@TargetApi(21)
+public abstract class ConstraintTestActivity extends PassFailButtons.Activity {
+ /**
+ * Intent we use to force the job scheduler to consider any ready jobs that otherwise it may
+ * have decided to be lazy about.
+ */
+ protected static final Intent EXPEDITE_STABLE_CHARGING =
+ new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE");
+
+ protected ComponentName mMockComponent;
+
+ protected MockJobService.TestEnvironment mTestEnvironment;
+ protected JobScheduler mJobScheduler;
+
+ /** Avoid cases where user might press "start test" more than once. */
+ private boolean mTestInProgress;
+ /**
+ * Starts the test - set up by subclass, which also controls the logic for how/when the test
+ * can be started.
+ */
+ protected Button mStartButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ mMockComponent = new ComponentName(this, MockJobService.class);
+ mTestEnvironment = MockJobService.TestEnvironment.getTestEnvironment();
+ }
+
+ /** OnClickListener for the "Start Test" ({@link #mStartButton}) button */
+ public final void startTest(View v) {
+ if (mTestInProgress) {
+ Toast toast =
+ Toast.makeText(
+ ConstraintTestActivity.this,
+ "Test already in progress",
+ Toast.LENGTH_SHORT);
+ toast.show();
+ return;
+ } else {
+ mTestInProgress = true;
+ startTestImpl();
+ }
+ }
+
+ /** Called by subclasses to allow the user to rerun the test if necessary. */
+ protected final void notifyTestCompleted() {
+ mTestInProgress = false;
+ }
+
+ /** Implemented by subclasses to determine logic for running the test. */
+ protected abstract void startTestImpl();
+
+ /**
+ * Broadcast the provided intent, and register a receiver to notify us after the broadcast has
+ * been processed.
+ * This function will block until the broadcast comes back, and <bold>cannot</bold> be called
+ * on the main thread.
+ * @return True if we received the callback, false if not.
+ */
+ protected boolean sendBroadcastAndBlockForResult(Intent intent) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ latch.countDown();
+ }
+ }, null, -1, null, null);
+ try {
+ return latch.await(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ /** Extended by test activities to report results of a test. */
+ protected abstract class TestResultRunner implements Runnable {
+ final int mJobId;
+ final boolean mTestPassed;
+
+ TestResultRunner(int jobId, boolean testPassed) {
+ mJobId = jobId;
+ mTestPassed = testPassed;
+ }
+ protected void noteInvalidTest() {
+ final Toast toast =
+ Toast.makeText(
+ ConstraintTestActivity.this,
+ "Invalid result returned from test thread: job=" + mJobId + ", res="
+ + mTestPassed,
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
new file mode 100644
index 0000000..a8bd993
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 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.verifier.jobscheduler;
+
+import com.android.cts.verifier.R;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ImageView;
+
+/**
+ * Idle constraints:
+ * The framework doesn't support turning idle mode off. Use the manual tester to ensure that
+ * the device is not in idle mode (by turning the screen off and then back on) before running
+ * the tests.
+ */
+@TargetApi(21)
+public class IdleConstraintTestActivity extends ConstraintTestActivity {
+ private static final String TAG = "IdleModeTestActivity";
+ /**
+ * It takes >1hr for idle mode to be triggered. We'll use this secret broadcast to force the
+ * scheduler into idle. It's not a protected broadcast so that's alright.
+ */
+ private static final String ACTION_EXPEDITE_IDLE_MODE =
+ "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
+
+ /**
+ * Id for the job that we schedule when the device is not in idle mode. This job is expected
+ * to not execute. Executing means that the verifier test should fail.
+ */
+ private static final int IDLE_OFF_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 0;
+ /**
+ * Id for the job that we schedule when the device *is* in idle mode. This job is expected to
+ * execute. Not executing means that the verifier test should fail.
+ */
+ private static final int IDLE_ON_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 1;
+
+ /**
+ * Listens for idle mode off/on events, namely {@link #ACTION_EXPEDITE_IDLE_MODE} and
+ * {@link Intent#ACTION_SCREEN_ON}.
+ * On ACTION_EXPEDITE_IDLE_MODE, we will disable the {@link #mStartButton}, and on
+ * ACTION_SCREEN_ON we enable it. This is to avoid the start button being clicked when the
+ * device is in idle mode.
+ */
+ private BroadcastReceiver mIdleChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+ mStartButton.setEnabled(true);
+ } else if (ACTION_EXPEDITE_IDLE_MODE.equals(intent.getAction())) {
+ mStartButton.setEnabled(false);
+ } else {
+ Log.e(TAG, "Invalid broadcast received, was expecting SCREEN_ON");
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set up the UI.
+ setContentView(R.layout.js_idle);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.js_idle_test, R.string.js_idle_instructions, -1);
+ mStartButton = (Button) findViewById(R.id.js_idle_start_test_button);
+
+ // Register receiver for idle off/on events.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+ intentFilter.addAction(ACTION_EXPEDITE_IDLE_MODE);
+
+ registerReceiver(mIdleChangedReceiver, intentFilter);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mIdleChangedReceiver);
+ }
+
+ @Override
+ protected void startTestImpl() {
+ new TestIdleModeTask().execute();
+ }
+
+ /** Background task that will run the actual test. */
+ private class TestIdleModeTask extends AsyncTask<Void, Void, Void> {
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+ testIdleConstraintFails_notIdle();
+
+
+ // Send the {@link #ACTION_EXPEDITE_IDLE_MODE} broadcast as an ordered broadcast, this
+ // function will block until all receivers have processed the broadcast.
+ if (!sendBroadcastAndBlockForResult(new Intent(ACTION_EXPEDITE_IDLE_MODE))) {
+ // Fail the test if the broadcast wasn't processed.
+ runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, false));
+ }
+
+ testIdleConstraintExecutes_onIdle();
+
+ notifyTestCompleted();
+ return null;
+ }
+
+ }
+
+ /**
+ * The user has just pressed the "Start Test" button, so we know that the device can't be idle.
+ * Schedule a job with an idle constraint and verify that it doesn't execute.
+ */
+ private void testIdleConstraintFails_notIdle() {
+ mTestEnvironment.setUp();
+ mJobScheduler.cancelAll();
+
+ mTestEnvironment.setExpectedExecutions(0);
+
+ mJobScheduler.schedule(
+ new JobInfo.Builder(IDLE_OFF_JOB_ID, mMockComponent)
+ .setRequiresDeviceIdle(true)
+ .build());
+
+ boolean testPassed;
+ try {
+ testPassed = mTestEnvironment.awaitTimeout();
+ } catch (InterruptedException e) {
+ // We'll just indicate that it failed, not why.
+ testPassed = false;
+ }
+ runOnUiThread(new IdleTestResultRunner(IDLE_OFF_JOB_ID, testPassed));
+ }
+
+ private void testIdleConstraintExecutes_onIdle() {
+ mTestEnvironment.setUp();
+ mJobScheduler.cancelAll();
+
+ mTestEnvironment.setExpectedExecutions(1);
+
+ mJobScheduler.schedule(
+ new JobInfo.Builder(IDLE_ON_JOB_ID, mMockComponent)
+ .setRequiresDeviceIdle(true)
+ .build());
+
+ boolean testPassed;
+ try {
+ testPassed = mTestEnvironment.awaitExecution();
+ } catch (InterruptedException e) {
+ // We'll just indicate that it failed, not why.
+ testPassed = false;
+ }
+ runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, testPassed));
+ }
+
+ /**
+ * Runnable to update the UI with the outcome of the test. This class only runs two tests, so
+ * the argument passed into the constructor will indicate which of the tests we are reporting
+ * for.
+ */
+ protected class IdleTestResultRunner extends TestResultRunner {
+
+ IdleTestResultRunner(int jobId, boolean testPassed) {
+ super(jobId, testPassed);
+ }
+
+ @Override
+ public void run() {
+ ImageView view;
+ if (mJobId == IDLE_OFF_JOB_ID) {
+ view = (ImageView) findViewById(R.id.idle_off_test_image);
+ } else if (mJobId == IDLE_ON_JOB_ID) {
+ view = (ImageView) findViewById(R.id.idle_on_test_image);
+ } else {
+ noteInvalidTest();
+ return;
+ }
+ view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java
new file mode 100644
index 0000000..9595a6a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 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.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this
+ * class is configured through the static
+ * {@link TestEnvironment}.
+ */
+@TargetApi(21)
+public class MockJobService extends JobService {
+ private static final String TAG = "MockJobService";
+
+ /** Wait this long before timing out the test. */
+ private static final long DEFAULT_TIMEOUT_MILLIS = 5000L; // 5 seconds.
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.e(TAG, "Created test service.");
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ Log.i(TAG, "Test job executing: " + params.getJobId());
+
+ TestEnvironment.getTestEnvironment().notifyExecution(params.getJobId());
+ return false; // No work to do.
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+
+ /**
+ * Configures the expected behaviour for each test. This object is shared across consecutive
+ * tests, so to clear state each test is responsible for calling
+ * {@link TestEnvironment#setUp()}.
+ */
+ public static final class TestEnvironment {
+
+ private static TestEnvironment kTestEnvironment;
+ public static final int INVALID_JOB_ID = -1;
+
+ private CountDownLatch mLatch;
+ private int mExecutedJobId;
+
+ public static TestEnvironment getTestEnvironment() {
+ if (kTestEnvironment == null) {
+ kTestEnvironment = new TestEnvironment();
+ }
+ return kTestEnvironment;
+ }
+
+ /**
+ * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
+ * job on this service.
+ */
+ public boolean awaitExecution() throws InterruptedException {
+ final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ return executed;
+ }
+
+ /**
+ * Block the test thread, expecting to timeout but still listening to ensure that no jobs
+ * land in the interim.
+ * @return True if the latch timed out waiting on an execution.
+ */
+ public boolean awaitTimeout() throws InterruptedException {
+ return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ private void notifyExecution(int jobId) {
+ Log.d(TAG, "Job executed:" + jobId);
+ mExecutedJobId = jobId;
+ mLatch.countDown();
+ }
+
+ public void setExpectedExecutions(int numExecutions) {
+ // For no executions expected, set count to 1 so we can still block for the timeout.
+ if (numExecutions == 0) {
+ mLatch = new CountDownLatch(1);
+ } else {
+ mLatch = new CountDownLatch(numExecutions);
+ }
+ }
+
+ /** Called in each testCase#setup */
+ public void setUp() {
+ mLatch = null;
+ mExecutedJobId = INVALID_JOB_ID;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
index f992618..510a03b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
@@ -26,6 +26,9 @@
import android.graphics.PixelFormat;
import android.media.Image;
import android.media.ImageReader;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -68,7 +71,7 @@
protected TestStatus mTestStatus = TestStatus.RUNNING;
private final Runnable sendKeyEventRunnable = new Runnable() {
- @Override
+ @Override
public void run() {
try {
mService.onKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
@@ -79,15 +82,28 @@
}
};
+ private final Runnable playNotificationRunnable = new Runnable() {
+
+ @Override
+ public void run() {
+ Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+ Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
+ r.play();
+ }
+ };
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
- new Handler(Looper.getMainLooper()).postDelayed(
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.postDelayed(
sendKeyEventRunnable, DELAYED_RUNNABLE_TIME);
mStatusView.setText("Running test...");
mTimeScreenTurnedOff = SystemClock.uptimeMillis();
+ // Notify user its safe to turn screen back on after 5s + fudge factor
+ handler.postDelayed(playNotificationRunnable, TIME_SCREEN_OFF + 500);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
if (SystemClock.uptimeMillis() - mTimeScreenTurnedOff < TIME_SCREEN_OFF) {
mStatusView.setText("ERROR: Turned on screen too early");
@@ -121,8 +137,9 @@
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mReceiver, filter);
- mStatusView.setText(
- "Please turn off your screen and turn it back on after 5 seconds");
+ mStatusView.setText("Please turn off your screen and turn it back on after " +
+ "5 seconds. A sound will be played when it is safe to turn the " +
+ "screen back on");
}
});
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
index 82f8ae9..36559bd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
@@ -23,6 +23,8 @@
import android.os.Build;
import android.provider.Settings;
+import java.lang.reflect.Field;
+
/**
* A helper class that provides a mechanism to:
* - prompt users to activate/deactivate features that are known to register for sensor data.
@@ -37,6 +39,7 @@
private final SensorSettingContainer mAirplaneMode = new AirplaneModeSettingContainer();
private final SensorSettingContainer mScreenBrightnessMode =
new ScreenBrightnessModeSettingContainer();
+ private final SensorSettingContainer mAmbientDisplayMode = new AmbientDisplaySettingContainer();
private final SensorSettingContainer mAutoRotateScreenMode =
new AutoRotateScreenModeSettingContainer();
private final SensorSettingContainer mKeepScreenOnMode = new KeepScreenOnModeSettingContainer();
@@ -51,6 +54,7 @@
mAirplaneMode.requestToSetMode(mStateContainer, true);
mScreenBrightnessMode.requestToSetMode(mStateContainer, false);
+ mAmbientDisplayMode.requestToSetMode(mStateContainer, false);
mAutoRotateScreenMode.requestToSetMode(mStateContainer, false);
mKeepScreenOnMode.requestToSetMode(mStateContainer, false);
mLocationMode.requestToSetMode(mStateContainer, false);
@@ -70,6 +74,7 @@
mAirplaneMode.requestToResetMode(mStateContainer);
mScreenBrightnessMode.requestToResetMode(mStateContainer);
+ mAmbientDisplayMode.requestToResetMode(mStateContainer);
mAutoRotateScreenMode.requestToResetMode(mStateContainer);
mKeepScreenOnMode.requestToResetMode(mStateContainer);
mLocationMode.requestToResetMode(mStateContainer);
@@ -78,6 +83,7 @@
private void captureInitialState() {
mAirplaneMode.captureInitialState();
mScreenBrightnessMode.captureInitialState();
+ mAmbientDisplayMode.captureInitialState();
mAutoRotateScreenMode.captureInitialState();
mLocationMode.captureInitialState();
mKeepScreenOnMode.captureInitialState();
@@ -116,6 +122,37 @@
}
}
+ private class AmbientDisplaySettingContainer extends SensorSettingContainer {
+ public AmbientDisplaySettingContainer() {
+ super(Settings.ACTION_DISPLAY_SETTINGS, R.string.snsr_setting_ambient_display);
+ }
+
+ @Override
+ protected int getSettingMode(int defaultValue) {
+ // TODO: replace the use of reflection with Settings.Secure.DOZE_ENABLED when the
+ // static field is not hidden anymore
+ Class<?> secureSettingsClass = Settings.Secure.class;
+ Field dozeEnabledField;
+ try {
+ dozeEnabledField = secureSettingsClass.getField("DOZE_ENABLED");
+ } catch (NoSuchFieldException e) {
+ return defaultValue;
+ }
+
+ String settingName;
+ try {
+ settingName = (String) dozeEnabledField.get(null /* obj */);
+ } catch (IllegalAccessException e) {
+ return defaultValue;
+ }
+
+ return Settings.Secure.getInt(
+ mStateContainer.getContentResolver(),
+ settingName,
+ defaultValue);
+ }
+ }
+
private class AutoRotateScreenModeSettingContainer extends SensorSettingContainer {
public AutoRotateScreenModeSettingContainer() {
super(Settings.ACTION_ACCESSIBILITY_SETTINGS,
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 83187c7..fe8f9ee 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -30,6 +30,7 @@
import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.MoreAsserts;
+import android.text.format.DateUtils;
import com.android.cts.documentclient.MyActivity.Result;
@@ -47,6 +48,8 @@
private UiDevice mDevice;
private MyActivity mActivity;
+ private static final long TIMEOUT = 10 * DateUtils.SECOND_IN_MILLIS;
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -54,6 +57,7 @@
mDevice = UiDevice.getInstance(getInstrumentation());
mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
MyActivity.class, null);
+ mDevice.waitForIdle();
}
@Override
@@ -78,7 +82,8 @@
mActivity.startActivityForResult(intent, 42);
// Ensure that we see both of our roots
- assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).exists());
+ mDevice.waitForIdle();
+ assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).waitForExists(TIMEOUT));
assertTrue("CtsCreate root", new UiObject(new UiSelector().text("CtsCreate")).exists());
assertFalse("CtsGetContent", new UiObject(new UiSelector().text("CtsGetContent")).exists());
@@ -86,8 +91,6 @@
mDevice.waitForIdle();
new UiObject(new UiSelector().text("CtsLocal")).click();
- // make sure drawer is expanded?
-
mDevice.waitForIdle();
new UiObject(new UiSelector().text("FILE1")).click();
@@ -148,6 +151,7 @@
mDevice.waitForIdle();
new UiObject(new UiSelector().text("FILE1")).click();
+ mDevice.waitForIdle();
new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
.childSelector(new UiSelector().resourceId("android:id/button1"))).click();
@@ -237,16 +241,15 @@
intent.setType("*/*");
mActivity.startActivityForResult(intent, 42);
- mDevice.waitForIdle();
-
// Look around, we should be able to see both DocumentsProviders and
// other GET_CONTENT sources.
- assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).exists());
+ mDevice.waitForIdle();
+ assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).waitForExists(TIMEOUT));
assertTrue("CtsCreate root", new UiObject(new UiSelector().text("CtsCreate")).exists());
assertTrue("CtsGetContent", new UiObject(new UiSelector().text("CtsGetContent")).exists());
- new UiObject(new UiSelector().text("CtsGetContent")).click();
mDevice.waitForIdle();
+ new UiObject(new UiSelector().text("CtsGetContent")).click();
final Result result = mActivity.getResult();
assertEquals("ReSuLt", result.data.getAction());
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
index 17dc3f1..59f0752 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
@@ -22,12 +22,11 @@
import android.util.Log;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.IOException;
import java.io.OutputStreamWriter;
-
/**
* Class to receive intents sent across profile boundaries, and read/write to content uri specified
* in these intents to test cross-profile content uris.
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
new file mode 100644
index 0000000..e45ec31
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2014 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 := CtsIntentSenderApp
+
+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
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml b/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
new file mode 100644
index 0000000..070ef40
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.intent.sender">
+
+ <uses-sdk android:minSdkVersion="19" />
+
+ <permission
+ android:name="com.android.cts.intent.sender.permission.SAMPLE"
+ android:label="Sample Permission" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".IntentSenderActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+
+ <provider
+ android:name="android.support.v4.content.FileProvider"
+ android:authorities="com.android.cts.intent.sender.fileprovider"
+ android:grantUriPermissions="true"
+ android:exported="false">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/filepaths" />
+ </provider>
+
+ <provider
+ android:name=".BasicContentProvider"
+ android:authorities="com.android.cts.intent.sender.provider"
+ android:grantUriPermissions="true"
+ android:exported="true"
+ android:permission="com.android.cts.intent.sender.permission.SAMPLE" />
+
+ </application>
+
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.cts.intent.sender"
+ android:label="Intent Sender CTS Tests" />
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/filepaths.xml b/hostsidetests/devicepolicy/app/IntentSender/res/xml/filepaths.xml
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/res/xml/filepaths.xml
rename to hostsidetests/devicepolicy/app/IntentSender/res/xml/filepaths.xml
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/BasicContentProvider.java
similarity index 96%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java
rename to hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/BasicContentProvider.java
index f91d404..183ab9f 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/BasicContentProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.managedprofile.crossprofilecontent;
+package com.android.cts.intent.sender;
import android.content.ContentProvider;
import android.content.ContentValues;
@@ -69,4 +69,3 @@
new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
}
}
-
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderActivity.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderActivity.java
new file mode 100644
index 0000000..00fa6b7
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 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.intent.sender;
+
+import android.app.Activity;
+import android.content.Intent;
+
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+
+public class IntentSenderActivity extends Activity {
+
+ private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+
+ public static class Result {
+ public final int resultCode;
+ public final Intent data;
+
+ public Result(int resultCode, Intent data) {
+ this.resultCode = resultCode;
+ this.data = data;
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK) {
+ try {
+ mResult.offer(new Result(resultCode, data), 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public Intent getResult(Intent intent) throws Exception {
+ startActivityForResult(intent, 42);
+ final Result result = mResult.poll(30, TimeUnit.SECONDS);
+ return (result != null) ? result.data : null;
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderTest.java
similarity index 76%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
rename to hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderTest.java
index 85e7d1b..47de0da 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderTest.java
@@ -13,30 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.managedprofile.crossprofilecontent;
-import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
+package com.android.cts.intent.sender;
-import android.app.admin.DevicePolicyManager;
import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.net.Uri;
import android.support.v4.content.FileProvider;
-import android.test.ActivityInstrumentationTestCase2;
+import android.test.InstrumentationTestCase;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.IOException;
-public class CrossProfileContentTest extends
- ActivityInstrumentationTestCase2<IntentSenderActivity> {
+public class IntentSenderTest extends InstrumentationTestCase {
private static final String MESSAGE = "Sample Message";
@@ -49,35 +45,20 @@
private static final String TAG = "CrossProfileContentTest";
- private static final String BASIC_CONTENT_PROVIDER_AUTHORITY =
- "com.android.cts.managedprofile.basiccontentProvider";
-
-
- private DevicePolicyManager mDpm;
-
private Context mContext;
-
- public CrossProfileContentTest() {
- super(IntentSenderActivity.class);
- }
+ private IntentSenderActivity mActivity;
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getTargetContext();
- mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ACTION_READ_FROM_URI);
- intentFilter.addAction(ACTION_WRITE_TO_URI);
- intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
- mDpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
- DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+ mActivity = launchActivity(mContext.getPackageName(), IntentSenderActivity.class, null);
}
@Override
- protected void tearDown() throws Exception {
- mDpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
+ public void tearDown() throws Exception {
super.tearDown();
+ mActivity.finish();
}
/**
@@ -85,14 +66,15 @@
* This intent will have, in the ClipData, a uri whose associated file stores a message.
* The receiver will read the message from the uri, and put it inside the result intent.
*/
- public void testReceiverCanRead() {
+ public void testReceiverCanRead() throws Exception {
Uri uri = getUriWithTextInFile("reading_test", MESSAGE);
assertTrue(uri != null);
Intent intent = new Intent(ACTION_READ_FROM_URI);
intent.setClipData(ClipData.newRawUri("", uri));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- Intent result = getActivity().getResultForIntent(intent);
- assertTrue(result != null);
+
+ final Intent result = mActivity.getResult(intent);
+ assertNotNull(result);
assertEquals(MESSAGE, result.getStringExtra("extra_response"));
}
@@ -102,7 +84,7 @@
* The receiver will read the message from the extra, and write it to the uri in
* the ClipData.
*/
- public void testReceiverCanWrite() {
+ public void testReceiverCanWrite() throws Exception {
// It's the receiver of the intent that should write to the uri, not us. So, for now, we
// write an empty string.
Uri uri = getUriWithTextInFile("writing_test", "");
@@ -112,19 +94,21 @@
intent.putExtra("extra_message", MESSAGE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
- getActivity().getResultForIntent(intent);
+
+ mActivity.getResult(intent);
assertEquals(MESSAGE, getFirstLineFromUri(uri));
}
- public void testPersistablePermission() {
+ public void testPersistablePermission() throws Exception {
Uri uri = getUriWithTextInFile("persistable_test", MESSAGE);
grantPersistableReadPermission(uri);
// Now checking if the receiver can read this uri, without re-granting the read permission.
Intent intent = new Intent(ACTION_READ_FROM_URI);
intent.setClipData(ClipData.newRawUri("", uri));
- Intent result = getActivity().getResultForIntent(intent);
- assertTrue(result != null);
+
+ final Intent result = mActivity.getResult(intent);
+ assertNotNull(result);
assertEquals(MESSAGE, result.getStringExtra("extra_response"));
}
@@ -138,7 +122,7 @@
* uriNotGranted), to enforce that even if an app has permission to one uri of a
* ContentProvider, it still cannot access a uri it does not have access to.
*/
- public void testAppPermissionsDontWorkAcrossProfiles() {
+ public void testAppPermissionsDontWorkAcrossProfiles() throws Exception {
// The FileProvider does not allow to use app permissions. So we need to use another
// ContentProvider.
Uri uriGranted = getBasicContentProviderUri("uri_granted");
@@ -152,19 +136,41 @@
Intent notGrant = new Intent(ACTION_READ_FROM_URI);
notGrant.setClipData(ClipData.newRawUri("", uriNotGranted));
- Intent result = getActivity().getResultForIntent(notGrant);
- assertTrue(result != null);
+ final Intent result = mActivity.getResult(notGrant);
+ assertNotNull(result);
// The receiver did not have permission to read the uri. So it should have caught a security
// exception.
assertTrue(result.getBooleanExtra("extra_caught_security_exception", false));
}
- private void grantPersistableReadPermission(Uri uri) {
+ /**
+ * Ensure that sender is only able to send data that it has access to.
+ */
+ public void testSecurity() throws Exception {
+ // Pick a URI that neither of us have access to; it doens't matter if
+ // its missing, since we expect a SE before a FNFE.
+ final Uri uri = Uri.parse("content://media/external/images/media/10240");
+ final Intent intent = new Intent(ACTION_READ_FROM_URI);
+ intent.setClipData(ClipData.newRawUri("", uri));
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // We're expecting to run into a security exception
+ final Intent result = mActivity.getResult(intent);
+ if (result == null) {
+ // This is fine; probably of a SecurityException when off in the
+ // system somewhere.
+ } else {
+ // But if we somehow came through, make sure they threw.
+ assertTrue(result.getBooleanExtra("extra_caught_security_exception", false));
+ }
+ }
+
+ private void grantPersistableReadPermission(Uri uri) throws Exception {
Intent grantPersistable = new Intent(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
grantPersistable.setClipData(ClipData.newRawUri("", uri));
grantPersistable.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
- getActivity().getResultForIntent(grantPersistable);
+ mActivity.getResult(grantPersistable);
}
private Uri getBasicContentProviderUri(String path) {
@@ -172,7 +178,7 @@
// granting these uris to other apps, or these apps from trying to access these uris.
return new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
- .authority(BASIC_CONTENT_PROVIDER_AUTHORITY)
+ .authority("com.android.cts.intent.sender.provider")
.path(path)
.build();
}
@@ -191,7 +197,7 @@
Log.e(TAG, "Could not create file " + filename + " with text " + text);
return null;
}
- return FileProvider.getUriForFile(mContext, "com.android.cts.managedprofile.fileprovider",
+ return FileProvider.getUriForFile(mContext, "com.android.cts.intent.sender.fileprovider",
file);
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 56b3671..008ed38 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -19,9 +19,6 @@
<uses-sdk android:minSdkVersion="20"/>
- <permission android:name="com.android.cts.managedprofile.permission.SAMPLE"
- android:label="Sample Permission"/>
-
<application>
<uses-library android:name="android.test.runner" />
<receiver
@@ -65,11 +62,6 @@
<action android:name="com.android.cts.managedprofile.ACTION_TEST_ALL_ACTIVITY" />
</intent-filter>
</activity>
- <activity android:name=".crossprofilecontent.IntentSenderActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- </intent-filter>
- </activity>
<activity android:name=".UserRestrictionActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -77,22 +69,6 @@
</intent-filter>
</activity>
<activity android:name=".TestActivity" />
- <provider
- android:name="android.support.v4.content.FileProvider"
- android:authorities="com.android.cts.managedprofile.fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/filepaths" />
- </provider>
- <provider
- android:name="com.android.cts.managedprofile.crossprofilecontent.BasicContentProvider"
- android:authorities="com.android.cts.managedprofile.basiccontentProvider"
- android:grantUriPermissions="true"
- android:exported="true"
- android:permission="com.android.cts.managedprofile.permission.SAMPLE"
- />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/AllUsersActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AllUsersActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/AllUsersActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AllUsersActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ComponentDisablingActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ComponentDisablingActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ComponentDisablingActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ComponentDisablingActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
new file mode 100644
index 0000000..9615991
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 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.managedprofile;
+
+import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.test.AndroidTestCase;
+
+public class CrossProfileUtils extends AndroidTestCase {
+ private static final String ACTION_READ_FROM_URI = "com.android.cts.action.READ_FROM_URI";
+
+ private static final String ACTION_WRITE_TO_URI = "com.android.cts.action.WRITE_TO_URI";
+
+ private static final String ACTION_TAKE_PERSISTABLE_URI_PERMISSION =
+ "com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION";
+
+ public void addParentCanAccessManagedFilters() {
+ removeAllFilters();
+
+ final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_READ_FROM_URI);
+ intentFilter.addAction(ACTION_WRITE_TO_URI);
+ intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
+ dpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
+ DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+ }
+
+ public void addManagedCanAccessParentFilters() {
+ removeAllFilters();
+
+ final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_READ_FROM_URI);
+ intentFilter.addAction(ACTION_WRITE_TO_URI);
+ intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
+ dpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
+ DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
+ }
+
+ public void removeAllFilters() {
+ final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ dpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileTest.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserActivity.java
similarity index 99%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserActivity.java
index 35f70be..b0e84ae 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserActivity.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserActivity.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.cts.managedprofile;
import android.app.Activity;
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserFilterSetterActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserFilterSetterActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserFilterSetterActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserFilterSetterActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
similarity index 99%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserTest.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
index 7098d9e..40ff6c5 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.cts.managedprofile;
import android.app.admin.DevicePolicyManager;
@@ -55,7 +56,7 @@
public void testAddCrossProfileIntentFilter_all() {
assertEquals(2, mPackageManager.queryIntentActivities(
new Intent(AllUsersActivity.ACTION), /* flags = */ 0).size());
-
+
// If we used startActivity(), the user would have a disambiguation dialog presented which
// requires human intervention, so we won't be testing like that
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/TestActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/TestActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/TestActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/TestActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
deleted file mode 100644
index e4c8ddf..0000000
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 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.managedprofile.crossprofilecontent;
-
-import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.util.Log;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class IntentSenderActivity extends Activity {
-
- private CountDownLatch mLatch;
-
- private static final int WAIT_FOR_RESPONSE_TIMEOUT_SECONDS = 5;
-
- private Intent mResult;
-
- Intent getResultForIntent(Intent intent) {
- mLatch = new CountDownLatch(1);
- mResult = null;
- startActivityForResult(intent, 0);
- try {
- mLatch.await(WAIT_FOR_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- }
- return mResult;
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent result) {
- if (resultCode == Activity.RESULT_OK) {
- mResult = result;
- }
- mLatch.countDown();
- }
-}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 15c7725..544ddff 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -17,6 +17,7 @@
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;
@@ -26,11 +27,13 @@
import com.android.ddmlib.testrunner.TestRunResult;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
+import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashSet;
@@ -74,6 +77,21 @@
installResult);
}
+ protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
+ DeviceNotAvailableException {
+ final ITestDevice device = getDevice();
+
+ final File apk = mCtsBuild.getTestApp(appFileName);
+ final String remotePath = "/data/local/tmp/" + apk.getName();
+ if (!device.pushFile(apk, remotePath)) {
+ throw new IllegalStateException("Failed to push " + apk);
+ }
+
+ final String result = device.executeShellCommand(
+ "pm install --user " + userId + " " + remotePath);
+ assertTrue(result, result.contains("\nSuccess"));
+ }
+
/** Initializes the user with the given id. This is required so that apps can run on it. */
protected void startUser(int userId) throws DeviceNotAvailableException {
String command = "am start-user " + userId;
@@ -135,7 +153,17 @@
protected boolean runDeviceTestsAsUser(
String pkgName, @Nullable String testClassName, int userId)
throws DeviceNotAvailableException {
- return runDeviceTests(pkgName, testClassName, null /*testMethodName*/, userId);
+ return runDeviceTestsAsUser(pkgName, testClassName, null, userId);
+ }
+
+ /** Returns true if the specified tests passed. Tests are run as given user. */
+ protected boolean runDeviceTestsAsUser(
+ String pkgName, @Nullable String testClassName, String testMethodName, int userId)
+ throws DeviceNotAvailableException {
+ if (testClassName.startsWith(".")) {
+ testClassName = pkgName + testClassName;
+ }
+ return runDeviceTests(pkgName, testClassName, testMethodName, userId);
}
private boolean runDeviceTests(String pkgName, @Nullable String testClassName,
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 88a3b70..6ece85c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -28,6 +28,9 @@
private static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
+ private static final String INTENT_SENDER_PKG = "com.android.cts.intent.sender";
+ private static final String INTENT_SENDER_APK = "CtsIntentSenderApp.apk";
+
private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
@@ -110,16 +113,30 @@
if (!mHasFeature) {
return;
}
+
try {
- installApp(INTENT_RECEIVER_APK);
+ getDevice().uninstallPackage(INTENT_SENDER_PKG);
+ getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+ installAppAsUser(INTENT_SENDER_APK, 0);
+ installAppAsUser(INTENT_RECEIVER_APK, mUserId);
- String command = "pm uninstall --user " + mUserId + " " + INTENT_RECEIVER_PKG;
- CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
- + getDevice().executeShellCommand(command));
+ // Test from parent to managed
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+ "addManagedCanAccessParentFilters", mUserId));
+ assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".IntentSenderTest", 0));
- assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
- MANAGED_PROFILE_PKG + ".crossprofilecontent.CrossProfileContentTest", mUserId));
+ getDevice().uninstallPackage(INTENT_SENDER_PKG);
+ getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+ installAppAsUser(INTENT_SENDER_APK, mUserId);
+ installAppAsUser(INTENT_RECEIVER_APK, 0);
+
+ // Test from managed to parent
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+ "addParentCanAccessManagedFilters", mUserId));
+ assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".IntentSenderTest", mUserId));
+
} finally {
+ getDevice().uninstallPackage(INTENT_SENDER_PKG);
getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
}
}
diff --git a/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java b/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
index 997f730..d74ddb2 100644
--- a/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
+++ b/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
@@ -17,6 +17,7 @@
package com.android.cts.browser;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.cts.util.WatchDog;
import android.net.Uri;
import android.provider.Browser;
@@ -70,10 +71,12 @@
private volatile int mRunIndex;
/** stores results for each runs. last entry will be the final score. */
private LinkedHashMap<String, double[]> mResultsMap;
+ private PackageManager mPackageManager;
@Override
protected void setUp() throws Exception {
super.setUp();
+ mPackageManager = getInstrumentation().getContext().getPackageManager();
mWebServer = new CtsTestServer(getContext()) {
@Override
protected HttpResponse onPost(HttpRequest request) throws Exception {
@@ -124,6 +127,10 @@
@TimeoutReq(minutes = 60)
public void testOctane() throws InterruptedException {
+ if (!isBrowserSupported()) {
+ Log.i(TAG, "Skipping test for device with no supported browser");
+ return;
+ }
String url = mWebServer.getAssetUrl(OCTANE_START_FILE) + "?auto=1";
final int kRepeat = 5;
doTest(url, ResultType.LOWER_BETTER, ResultUnit.MS,
@@ -167,4 +174,13 @@
numberToProcess++;
}
}
+
+ /**
+ * @return true iff this device is has a working browser.
+ */
+ private boolean isBrowserSupported() {
+ return !(mPackageManager.hasSystemFeature("android.hardware.type.television")
+ || mPackageManager.hasSystemFeature("android.software.leanback")
+ || mPackageManager.hasSystemFeature("android.hardware.type.watch"));
+ }
}
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
new file mode 100755
index 0000000..499abde
--- /dev/null
+++ b/tests/JobScheduler/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2014 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)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_PACKAGE_NAME := CtsJobSchedulerDeviceTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobScheduler/AndroidManifest.xml b/tests/JobScheduler/AndroidManifest.xml
new file mode 100755
index 0000000..17cf399
--- /dev/null
+++ b/tests/JobScheduler/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2014 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="android.jobscheduler.cts.deviceside">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <service android:name="android.jobscheduler.MockJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:label="JobScheduler device-side tests"
+ android:targetPackage="android.jobscheduler.cts.deviceside" >
+ <meta-data
+ android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
+
diff --git a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
new file mode 100644
index 0000000..a0177e2
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 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 android.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this
+ * class is configured through the static
+ * {@link TestEnvironment}.
+ */
+@TargetApi(21)
+public class MockJobService extends JobService {
+ private static final String TAG = "MockJobService";
+
+ /** Wait this long before timing out the test. */
+ private static final long DEFAULT_TIMEOUT_MILLIS = 5000L; // 5 seconds.
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.e(TAG, "Created test service.");
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ Log.i(TAG, "Test job executing: " + params.getJobId());
+
+ TestEnvironment.getTestEnvironment().notifyExecution(params.getJobId());
+ return false; // No work to do.
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+
+ /**
+ * Configures the expected behaviour for each test. This object is shared across consecutive
+ * tests, so to clear state each test is responsible for calling
+ * {@link TestEnvironment#setUp()}.
+ */
+ public static final class TestEnvironment {
+
+ private static TestEnvironment kTestEnvironment;
+ public static final int INVALID_JOB_ID = -1;
+
+ private CountDownLatch mLatch;
+ private int mExecutedJobId;
+
+ public static TestEnvironment getTestEnvironment() {
+ if (kTestEnvironment == null) {
+ kTestEnvironment = new TestEnvironment();
+ }
+ return kTestEnvironment;
+ }
+
+ /**
+ * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
+ * job on this service.
+ */
+ public boolean awaitExecution() throws InterruptedException {
+ final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ return executed;
+ }
+
+ /**
+ * Block the test thread, expecting to timeout but still listening to ensure that no jobs
+ * land in the interim.
+ * @return True if the latch timed out waiting on an execution.
+ */
+ public boolean awaitTimeout() throws InterruptedException {
+ return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ private void notifyExecution(int jobId) {
+ Log.d(TAG, "Job executed:" + jobId);
+ mExecutedJobId = jobId;
+ mLatch.countDown();
+ }
+
+ public void setExpectedExecutions(int numExecutions) {
+ // For no executions expected, set count to 1 so we can still block for the timeout.
+ if (numExecutions == 0) {
+ mLatch = new CountDownLatch(1);
+ } else {
+ mLatch = new CountDownLatch(numExecutions);
+ }
+ }
+
+ /** Called in each testCase#setup */
+ public void setUp() {
+ mLatch = null;
+ mExecutedJobId = INVALID_JOB_ID;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
new file mode 100644
index 0000000..a83f7a9
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2014 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 android.jobscheduler.cts;
+
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Schedules jobs with the {@link android.app.job.JobScheduler} that have network connectivity
+ * constraints.
+ * Requires manipulating the {@link android.net.wifi.WifiManager} to ensure an unmetered network.
+ * Similarly, requires that the phone be connected to a wifi hotspot, or else the test will fail.
+ */
+@TargetApi(21)
+public class ConnectivityConstraintTest extends ConstraintTest {
+ private static final String TAG = "ConnectivityConstraintTest";
+
+ /** Unique identifier for the job scheduled by this suite of tests. */
+ public static final int CONNECTIVITY_JOB_ID = ConnectivityConstraintTest.class.hashCode();
+
+ private WifiManager mWifiManager;
+ private ConnectivityManager mCm;
+
+ /** Whether the device running these tests supports WiFi. */
+ private boolean mHasWifi;
+ /** Whether the device running these tests supports telephony. */
+ private boolean mHasTelephony;
+
+ private JobInfo.Builder mBuilder;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+ mCm =
+ (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ PackageManager packageManager = mContext.getPackageManager();
+ mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
+ mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ mBuilder =
+ new JobInfo.Builder(CONNECTIVITY_JOB_ID, kJobServiceComponent);
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Positives - schedule jobs under conditions that require them to pass.
+ // --------------------------------------------------------------------------------------------
+
+ /**
+ * Schedule a job that requires a WiFi connection, and assert that it executes when the device
+ * is connected to WiFi. This will fail if a wifi connection is unavailable.
+ */
+ public void testUnmeteredConstraintExecutes_withWifi() throws Exception {
+ if (!mHasWifi) {
+ Log.d(TAG, "Skipping test that requires the device be WiFi enabled.");
+ return;
+ }
+ connectToWiFi();
+
+ kTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(
+ mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+ .build());
+
+ sendExpediteStableChargingBroadcast();
+
+ assertTrue("Job with unmetered constraint did not fire on WiFi.",
+ kTestEnvironment.awaitExecution());
+ }
+
+ /**
+ * Schedule a job with a connectivity constraint, and ensure that it executes on WiFi.
+ */
+ public void testConnectivityConstraintExecutes_withWifi() throws Exception {
+ if (!mHasWifi) {
+ Log.d(TAG, "Skipping test that requires the device be WiFi enabled.");
+ return;
+ }
+ connectToWiFi();
+
+ kTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(
+ mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build());
+
+ sendExpediteStableChargingBroadcast();
+
+ assertTrue("Job with connectivity constraint did not fire on WiFi.",
+ kTestEnvironment.awaitExecution());
+ }
+
+ /**
+ * Schedule a job with a connectivity constraint, and ensure that it executes on on a mobile
+ * data connection.
+ */
+ public void testConnectivityConstraintExecutes_withMobile() throws Exception {
+ if (!checkDeviceSupportsMobileData()) {
+ return;
+ }
+ disconnectWifiToConnectToMobile();
+
+ kTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(
+ mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build());
+
+ sendExpediteStableChargingBroadcast();
+
+ assertTrue("Job with connectivity constraint did not fire on mobile.",
+ kTestEnvironment.awaitExecution());
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Negatives - schedule jobs under conditions that require that they fail.
+ // --------------------------------------------------------------------------------------------
+
+ /**
+ * Schedule a job that requires a WiFi connection, and assert that it fails when the device is
+ * connected to a cellular provider.
+ * This test assumes that if the device supports a mobile data connection, then this connection
+ * will be available.
+ */
+ public void testUnmeteredConstraintFails_withMobile() throws Exception {
+ if (!checkDeviceSupportsMobileData()) {
+ return;
+ }
+ disconnectWifiToConnectToMobile();
+
+ kTestEnvironment.setExpectedExecutions(0);
+ mJobScheduler.schedule(
+ mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+ .build());
+ sendExpediteStableChargingBroadcast();
+
+ assertTrue("Job requiring unmetered connectivity still executed on mobile.",
+ kTestEnvironment.awaitTimeout());
+ }
+
+ /**
+ * Determine whether the device running these CTS tests should be subject to tests involving
+ * mobile data.
+ * @return True if this device will support a mobile data connection.
+ */
+ private boolean checkDeviceSupportsMobileData() {
+ if (!mHasTelephony) {
+ Log.d(TAG, "Skipping test that requires telephony features, not supported by this" +
+ " device");
+ return false;
+ }
+ if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
+ Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Ensure WiFi is enabled, and block until we've verified that we are in fact connected.
+ * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
+ */
+ private void connectToWiFi() throws InterruptedException {
+ if (!mWifiManager.isWifiEnabled()) {
+ ConnectivityActionReceiver receiver =
+ new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI,
+ NetworkInfo.State.CONNECTED);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiver(receiver, filter);
+
+ assertTrue(mWifiManager.setWifiEnabled(true));
+ assertTrue("Wifi must be configured to connect to an access point for this test.",
+ receiver.waitForStateChange());
+
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+
+ private void disconnectWifiToConnectToMobile() throws InterruptedException {
+ if (mHasWifi && mWifiManager.isWifiEnabled()) {
+ ConnectivityActionReceiver connectMobileReceiver =
+ new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo.State.CONNECTED);
+ ConnectivityActionReceiver disconnectWifiReceiver =
+ new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI,
+ NetworkInfo.State.DISCONNECTED);
+ IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiver(connectMobileReceiver, filter);
+ mContext.registerReceiver(disconnectWifiReceiver, filter);
+
+ assertTrue(mWifiManager.setWifiEnabled(false));
+ assertTrue("Failure disconnecting from WiFi.",
+ disconnectWifiReceiver.waitForStateChange());
+ assertTrue("Device must have access to a metered network for this test.",
+ connectMobileReceiver.waitForStateChange());
+
+ mContext.unregisterReceiver(connectMobileReceiver);
+ mContext.unregisterReceiver(disconnectWifiReceiver);
+ }
+ }
+
+ /** Capture the last connectivity change's network type and state. */
+ private class ConnectivityActionReceiver extends BroadcastReceiver {
+
+ private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
+
+ private final int mNetworkType;
+
+ private final NetworkInfo.State mExpectedState;
+
+ ConnectivityActionReceiver(int networkType, NetworkInfo.State expectedState) {
+ mNetworkType = networkType;
+ mExpectedState = expectedState;
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ // Dealing with a connectivity changed event for this network type.
+ final int networkTypeChanged =
+ intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
+ if (networkTypeChanged == -1) {
+ Log.e(TAG, "No network type provided in intent");
+ return;
+ }
+
+ if (networkTypeChanged != mNetworkType) {
+ // Only track changes for the connectivity event that we are interested in.
+ return;
+ }
+ // Pull out the NetworkState object that we're interested in. Necessary because
+ // the ConnectivityManager will filter on uid for background connectivity.
+ NetworkInfo[] allNetworkInfo = mCm.getAllNetworkInfo();
+ NetworkInfo networkInfo = null;
+ for (int i=0; i<allNetworkInfo.length; i++) {
+ NetworkInfo ni = allNetworkInfo[i];
+ if (ni.getType() == mNetworkType) {
+ networkInfo = ni;
+ break;
+ }
+ }
+ if (networkInfo == null) {
+ Log.e(TAG, "Could not find correct network type.");
+ return;
+ }
+
+ NetworkInfo.State networkState = networkInfo.getState();
+ Log.i(TAG, "Network type: " + mNetworkType + " State: " + networkState);
+ if (networkState == mExpectedState) {
+ mReceiveLatch.countDown();
+ }
+ }
+
+ public boolean waitForStateChange() throws InterruptedException {
+ return mReceiveLatch.await(30, TimeUnit.SECONDS) || hasExpectedState();
+ }
+
+ private boolean hasExpectedState() {
+ return mExpectedState == mCm.getNetworkInfo(mNetworkType).getState();
+ }
+ }
+
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
new file mode 100644
index 0000000..b9a498f
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 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 android.jobscheduler.cts;
+
+import android.annotation.TargetApi;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.jobscheduler.MockJobService;
+import android.test.AndroidTestCase;
+
+/**
+ * Common functionality from which the other test case classes derive.
+ */
+@TargetApi(21)
+public abstract class ConstraintTest extends AndroidTestCase {
+ /** Force the scheduler to consider the device to be on stable charging. */
+ private static final Intent EXPEDITE_STABLE_CHARGING =
+ new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE");
+
+ /** Environment that notifies of JobScheduler callbacks. */
+ static MockJobService.TestEnvironment kTestEnvironment =
+ MockJobService.TestEnvironment.getTestEnvironment();
+ /** Handle for the service which receives the execution callbacks from the JobScheduler. */
+ static ComponentName kJobServiceComponent;
+ JobScheduler mJobScheduler;
+
+ @Override
+ public void setUp() throws Exception {
+ kTestEnvironment.setUp();
+ kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
+ mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ mJobScheduler.cancelAll();
+ }
+
+ /**
+ * The scheduler will usually only flush its queue of unexpired jobs when the device is
+ * considered to be on stable power - that is, plugged in for a period of 2 minutes.
+ * Rather than wait for this to happen, we cheat and send this broadcast instead.
+ */
+ protected void sendExpediteStableChargingBroadcast() {
+ getContext().sendBroadcast(EXPEDITE_STABLE_CHARGING);
+ }
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
new file mode 100644
index 0000000..36f44ef
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 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 android.jobscheduler.cts;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+
+/**
+ * Schedules jobs with various timing constraints and ensures that they are executed when
+ * appropriate.
+ */
+@TargetApi(21)
+public class TimingConstraintsTest extends ConstraintTest {
+ private static final int TIMING_JOB_ID = TimingConstraintsTest.class.hashCode() + 0;
+ private static final int CANCEL_JOB_ID = TimingConstraintsTest.class.hashCode() + 1;
+
+ public void testScheduleOnce() throws Exception {
+ JobInfo oneTimeJob = new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
+ .setOverrideDeadline(1000) // 1 secs
+ .build();
+
+ kTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(oneTimeJob);
+ final boolean executed = kTestEnvironment.awaitExecution();
+ assertTrue("Timed out waiting for override deadline.", executed);
+ }
+
+ public void testSchedulePeriodic() throws Exception {
+ JobInfo periodicJob =
+ new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
+ .setPeriodic(1000L) // 1 second period.
+ .build();
+
+ kTestEnvironment.setExpectedExecutions(3);
+ mJobScheduler.schedule(periodicJob);
+ final boolean countedDown = kTestEnvironment.awaitExecution();
+ assertTrue("Timed out waiting for periodic jobs to execute", countedDown);
+ }
+
+ public void testCancel() throws Exception {
+ JobInfo cancelJob = new JobInfo.Builder(CANCEL_JOB_ID, kJobServiceComponent)
+ .setOverrideDeadline(2000L)
+ .build();
+
+ kTestEnvironment.setExpectedExecutions(0);
+ mJobScheduler.schedule(cancelJob);
+ // Now cancel it.
+ mJobScheduler.cancel(CANCEL_JOB_ID);
+ assertTrue("Cancel failed: job executed when it shouldn't have.",
+ kTestEnvironment.awaitTimeout());
+ }
+}
\ No newline at end of file
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 8adf345..ae78695 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -1,5 +1,13 @@
[
{
+ description: "tests a fragile by nature as they rely on hardcoded behavior",
+ names: [
+ "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText",
+ "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverTextExtend"
+ ],
+ bug: 17595050
+},
+{
description: "signature test stil needs more work",
names: [
"android.signature.cts.SignatureTest#testSignature"
@@ -37,6 +45,26 @@
bug: 16720689
},
{
+ description: "test can only run properly on a user build device when the bug is resolved",
+ names: [
+ "android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks",
+ "android.appwidget.cts.AppWidgetTest#testBindAppWidget",
+ "android.appwidget.cts.AppWidgetTest#testCollectionWidgets",
+ "android.appwidget.cts.AppWidgetTest#testDeleteHost",
+ "android.appwidget.cts.AppWidgetTest#testDeleteHosts",
+ "android.appwidget.cts.AppWidgetTest#testGetAppWidgetIds",
+ "android.appwidget.cts.AppWidgetTest#testGetAppWidgetInfo",
+ "android.appwidget.cts.AppWidgetTest#testGetAppWidgetOptions",
+ "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetId",
+ "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetIds",
+ "android.appwidget.cts.AppWidgetTest#testTwoAppWidgetProviderCallbacks",
+ "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaComponentName",
+ "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId",
+ "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds"
+ ],
+ bug: 17993121
+},
+{
description: "A few WebGL tests are known to fail in WebView",
names: [
"android.webgl.cts.WebGLTest#test_conformance_extensions_oes_texture_float_with_video_html",
@@ -74,6 +102,13 @@
bug: 17530117
},
{
+ description: "this test removes the stay-awake option, causing the screen to turn off during the execution of subsequent tests",
+ names: [
+ "android.admin.cts.DevicePolicyManagerTest#testMaximumTimeToLock"
+ ],
+ bug: 18002490
+},
+{
description: "these tests locks the screen with an emtpy password or swipe-to-unlock, blocking subsequent test to dismiss keyguard",
names: [
"android.admin.cts.DevicePolicyManagerTest#testPasswordQuality_something",
@@ -322,5 +357,12 @@
"android.media.cts.ImageReaderDecoderTest#testHwAVCDecode360pForFlexibleYuv"
],
bug: 17144778
+},
+{
+ description: "Roboto font tests are not yet known good on all devices",
+ names: [
+ "android.uirendering.cts.testclasses.FontRenderingTests"
+ ],
+ bug: 17109280
}
]
diff --git a/tests/expectations/unsupportedabis.txt b/tests/expectations/unsupportedabis.txt
index 520d750..817179b 100644
--- a/tests/expectations/unsupportedabis.txt
+++ b/tests/expectations/unsupportedabis.txt
@@ -2,6 +2,14 @@
{
description: "Tests not supporting: arm64-v8a, x86_64, mips64",
names: [
+ "android.bionic.malloc#pvalloc_overflow",
+ "android.bionic.malloc#pvalloc_std",
+ "android.bionic.malloc#valloc_overflow",
+ "android.bionic.malloc#valloc_std",
+ "android.renderscriptlegacy.cts.LeakTest",
+ "android.renderscriptlegacy.cts.RSBase",
+ "android.renderscriptlegacy.cts.RSBaseCompute",
+ "android.renderscriptlegacy.cts.VersionTest",
"android.sample.cts.SampleDeviceResultTest",
"android.sample.cts.SampleDeviceTest",
"android.sample.cts.SampleHostResultTest",
diff --git a/tests/tests/usage/Android.mk b/tests/tests/app.usage/Android.mk
similarity index 100%
rename from tests/tests/usage/Android.mk
rename to tests/tests/app.usage/Android.mk
diff --git a/tests/tests/usage/AndroidManifest.xml b/tests/tests/app.usage/AndroidManifest.xml
similarity index 100%
rename from tests/tests/usage/AndroidManifest.xml
rename to tests/tests/app.usage/AndroidManifest.xml
diff --git a/tests/tests/usage/src/android/app/usage/cts/Activities.java b/tests/tests/app.usage/src/android/app/usage/cts/Activities.java
similarity index 100%
rename from tests/tests/usage/src/android/app/usage/cts/Activities.java
rename to tests/tests/app.usage/src/android/app/usage/cts/Activities.java
diff --git a/tests/tests/usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
similarity index 100%
rename from tests/tests/usage/src/android/app/usage/cts/UsageStatsTest.java
rename to tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index 1a048c6..e1afd50 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -8,6 +8,9 @@
LOCAL_MODULE := $(test_executable)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_ADDITION_DEPENDENCIES := \
$(LOCAL_PATH)/Android.mk \
@@ -31,6 +34,10 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := $(list_executable)
+LOCAL_MULTILIB := both
+# Use the 32 bit list executable since it will include some 32 bit only tests.
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_ADDITION_DEPENDENCIES := \
$(LOCAL_PATH)/Android.mk \
diff --git a/tests/tests/graphics/res/drawable/vector_icon_delete.xml b/tests/tests/graphics/res/drawable/vector_icon_delete.xml
index 7b8f2aa..8d9c21c 100644
--- a/tests/tests/graphics/res/drawable/vector_icon_delete.xml
+++ b/tests/tests/graphics/res/drawable/vector_icon_delete.xml
@@ -24,6 +24,6 @@
<path
android:fillColor="#FF000000"
- android:pathData="M6.0,19.0c0.0,1.104 896e-3,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0-896e-3 2.0-2.0l0.0-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
+ android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0-0.896 2.0-2.0l0.0-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_heart.xml b/tests/tests/graphics/res/drawable/vector_icon_heart.xml
index ad991c9..ff55fe5 100644
--- a/tests/tests/graphics/res/drawable/vector_icon_heart.xml
+++ b/tests/tests/graphics/res/drawable/vector_icon_heart.xml
@@ -24,6 +24,6 @@
<path
android:fillColor="#FF000000"
- android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
+ android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
</vector>
\ No newline at end of file
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index ea15c19..669de2d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -78,7 +78,7 @@
private static final int MAX_VIDEO_SNAPSHOT_IMAGES = 5;
private static final int BURST_VIDEO_SNAPSHOT_NUM = 3;
private static final int SLOWMO_SLOW_FACTOR = 4;
- private static final int MAX_NUM_FRAME_DROP_ALLOWED = 3;
+ private static final int MAX_NUM_FRAME_DROP_ALLOWED = 4;
private List<Size> mSupportedVideoSizes;
private Surface mRecordingSurface;
private MediaRecorder mMediaRecorder;
@@ -548,6 +548,8 @@
*/
private void videoSnapshotTestByCamera(boolean burstTest)
throws Exception {
+ final int NUM_SINGLE_SHOT_TEST = 5;
+ final int FRAMEDROP_TOLERANCE = 8;
for (int profileId : mCamcorderProfileList) {
int cameraId = Integer.valueOf(mCamera.getId());
if (!CamcorderProfile.hasProfile(cameraId, profileId) ||
@@ -603,70 +605,89 @@
+ videoSz.toString() + ".mp4";
}
- prepareRecordingWithProfile(profile);
+ int numTestIterations = burstTest ? 1 : NUM_SINGLE_SHOT_TEST;
+ int totalDroppedFrames = 0;
- // prepare video snapshot
- SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
- SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
- CaptureRequest.Builder videoSnapshotRequestBuilder =
- mCamera.createCaptureRequest((mStaticInfo.isHardwareLevelLegacy()) ?
- CameraDevice.TEMPLATE_RECORD : CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
+ for (int numTested = 0; numTested < numTestIterations; numTested++) {
+ prepareRecordingWithProfile(profile);
- // prepare preview surface by using video size.
- updatePreviewSurfaceWithVideoSize(videoSz);
+ // prepare video snapshot
+ SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+ SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
+ CaptureRequest.Builder videoSnapshotRequestBuilder =
+ mCamera.createCaptureRequest((mStaticInfo.isHardwareLevelLegacy()) ?
+ CameraDevice.TEMPLATE_RECORD :
+ CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
- prepareVideoSnapshot(videoSnapshotRequestBuilder, imageListener);
+ // prepare preview surface by using video size.
+ updatePreviewSurfaceWithVideoSize(videoSz);
- // Start recording
- startRecording(/* useMediaRecorder */true, resultListener);
- long startTime = SystemClock.elapsedRealtime();
+ prepareVideoSnapshot(videoSnapshotRequestBuilder, imageListener);
+ CaptureRequest request = videoSnapshotRequestBuilder.build();
- // Record certain duration.
- SystemClock.sleep(RECORDING_DURATION_MS / 2);
+ // Start recording
+ startRecording(/* useMediaRecorder */true, resultListener);
+ long startTime = SystemClock.elapsedRealtime();
- // take a video snapshot
- CaptureRequest request = videoSnapshotRequestBuilder.build();
- if (burstTest) {
- List<CaptureRequest> requests =
- new ArrayList<CaptureRequest>(BURST_VIDEO_SNAPSHOT_NUM);
- for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
- requests.add(request);
+ // Record certain duration.
+ SystemClock.sleep(RECORDING_DURATION_MS / 2);
+
+ // take video snapshot
+ if (burstTest) {
+ List<CaptureRequest> requests =
+ new ArrayList<CaptureRequest>(BURST_VIDEO_SNAPSHOT_NUM);
+ for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
+ requests.add(request);
+ }
+ mSession.captureBurst(requests, resultListener, mHandler);
+ } else {
+ mSession.capture(request, resultListener, mHandler);
}
- mSession.captureBurst(requests, resultListener, mHandler);
- } else {
- mSession.capture(request, resultListener, mHandler);
- }
- // make sure recording is still going after video snapshot
- SystemClock.sleep(RECORDING_DURATION_MS / 2);
+ // make sure recording is still going after video snapshot
+ SystemClock.sleep(RECORDING_DURATION_MS / 2);
- // Stop recording and preview
- stopRecording(/* useMediaRecorder */true);
- int duration = (int) (SystemClock.elapsedRealtime() - startTime);
+ // Stop recording and preview
+ stopRecording(/* useMediaRecorder */true);
+ int duration = (int) (SystemClock.elapsedRealtime() - startTime);
- // Validation recorded video
- validateRecording(videoSz, duration);
+ // Validation recorded video
+ validateRecording(videoSz, duration);
- if (burstTest) {
- for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
+ if (burstTest) {
+ for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
+ Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+ validateVideoSnapshotCapture(image, videoSnapshotSz);
+ image.close();
+ }
+ } else {
+ // validate video snapshot image
Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateVideoSnapshotCapture(image, videoSnapshotSz);
+
+ // validate if there is framedrop around video snapshot
+ totalDroppedFrames += validateFrameDropAroundVideoSnapshot(
+ resultListener, image.getTimestamp());
+
+ //TODO: validate jittering. Should move to PTS
+ //validateJittering(resultListener);
+
image.close();
}
- } else {
- // validate video snapshot image
- Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
- validateVideoSnapshotCapture(image, videoSnapshotSz);
-
- // validate if there is framedrop around video snapshot
- validateFrameDropAroundVideoSnapshot(resultListener, image.getTimestamp());
-
- //TODO: validate jittering. Should move to PTS
- //validateJittering(resultListener);
-
- image.close();
}
+ if (!burstTest) {
+ Log.w(TAG, String.format("Camera %d Video size %s: Number of dropped frames " +
+ "detected in %d trials is %d frames.", cameraId, videoSz.toString(),
+ numTestIterations, totalDroppedFrames));
+ mCollector.expectLessOrEqual(
+ String.format(
+ "Camera %d Video size %s: Number of dropped frames %d must not"
+ + " be larger than %d",
+ cameraId, videoSz.toString(), totalDroppedFrames,
+ FRAMEDROP_TOLERANCE),
+ FRAMEDROP_TOLERANCE, totalDroppedFrames);
+ }
closeImageReader();
}
}
@@ -867,8 +888,9 @@
/**
* Validate if video snapshot causes frame drop.
* Here frame drop is defined as frame duration >= 2 * expected frame duration.
+ * Return the estimated number of frames dropped during video snapshot
*/
- private void validateFrameDropAroundVideoSnapshot(
+ private int validateFrameDropAroundVideoSnapshot(
SimpleCaptureCallback resultListener, long imageTimeStamp) {
int expectedDurationMs = 1000 / mVideoFrameRate;
CaptureResult prevResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
@@ -883,6 +905,7 @@
resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
long nextTS = getValueNotNull(nextResult, CaptureResult.SENSOR_TIMESTAMP);
int durationMs = (int) (currentTS - prevTS) / 1000000;
+ int totalFramesDropped = 0;
// Snapshots in legacy mode pause the preview briefly. Skip the duration
// requirements for legacy mode unless this is fixed.
@@ -925,8 +948,18 @@
durationMs, expectedDurationMs
));
}
+
+ int totalDurationMs = (int) (nextTS - prevTS) / 1000000;
+ // Rounding and minus 2 for the expected 2 frames interval
+ totalFramesDropped =
+ (totalDurationMs + expectedDurationMs / 2) /expectedDurationMs - 2;
+ if (totalFramesDropped < 0) {
+ Log.w(TAG, "totalFrameDropped is " + totalFramesDropped +
+ ". Video frame rate might be too fast.");
+ }
+ totalFramesDropped = Math.max(0, totalFramesDropped);
}
- return;
+ return totalFramesDropped;
}
prevTS = currentTS;
}
diff --git a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
index f330e8a..3765809 100644
--- a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
+++ b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
@@ -227,15 +227,18 @@
@UiThreadTest
public void testGpsStatusListener() {
try {
- mManager.addGpsStatusListener(new MockGpsStatusListener());
- fail("Should have failed to add a gps status listener");
+ // .addGpsStatusListener returns true if the listener added successfully
+ if (mManager.addGpsStatusListener(new MockGpsStatusListener())) {
+ fail("Should have failed to add a gps status listener");
+ }
} catch (SecurityException e) {
// expected
}
try {
- mManager.addGpsStatusListener(null);
- fail("Should have failed to add a gps status listener");
+ if (mManager.addGpsStatusListener(null)) {
+ fail("Should have failed to add null as a gps status listener");
+ }
} catch (SecurityException e) {
// expected
}
diff --git a/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java b/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
index e993695..de5b698 100644
--- a/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
@@ -18,6 +18,7 @@
import com.android.cts.media.R;
+import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.audiofx.AcousticEchoCanceler;
@@ -47,6 +48,10 @@
//Test case 1.1: test NS creation and release
public void test1_1NsCreateAndRelease() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
AudioRecord ar = getAudioRecord();
assertNotNull("could not create AudioRecord", ar);
@@ -67,6 +72,10 @@
//Test case 1.2: test setEnabled() and getEnabled()
public void test1_2NsSetEnabledGetEnabled() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
if (!NoiseSuppressor.isAvailable()) {
return;
}
@@ -100,6 +109,10 @@
//Test case 2.1: test AEC creation and release
public void test2_1AecCreateAndRelease() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
AudioRecord ar = getAudioRecord();
assertNotNull("could not create AudioRecord", ar);
@@ -120,6 +133,10 @@
//Test case 2.2: test AEC setEnabled() and getEnabled()
public void test2_2AecSetEnabledGetEnabled() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
if (!AcousticEchoCanceler.isAvailable()) {
return;
}
@@ -153,6 +170,10 @@
//Test case 3.1: test AGC creation and release
public void test3_1AgcCreateAndRelease() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
AudioRecord ar = getAudioRecord();
assertNotNull("could not create AudioRecord", ar);
@@ -173,6 +194,10 @@
//Test case 3.2: test AGC setEnabled() and getEnabled()
public void test3_2AgcSetEnabledGetEnabled() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
if (!AutomaticGainControl.isAvailable()) {
return;
}
@@ -199,6 +224,10 @@
//-----------------------------------------------------------------
// private methods
//----------------------------------
+ private boolean hasMicrophone() {
+ return getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_MICROPHONE);
+ }
private AudioRecord getAudioRecord() {
AudioRecord ar = null;
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
index 3d18c47..cac97b3 100644
--- a/tests/tests/media/src/android/media/cts/VirtualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -53,6 +53,10 @@
//Test case 0.0: test constructor and release
public void test0_0ConstructorAndRelease() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
Virtualizer eq = null;
try {
eq = new Virtualizer(0, 0);
@@ -80,6 +84,10 @@
//Test case 1.0: test strength
public void test1_0Strength() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
getVirtualizer(0);
try {
if (mVirtualizer.getStrengthSupported()) {
@@ -108,6 +116,10 @@
//Test case 1.1: test properties
public void test1_1Properties() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
getVirtualizer(0);
try {
Virtualizer.Settings settings = mVirtualizer.getProperties();
@@ -141,6 +153,10 @@
//Test case 1.2: test setStrength() throws exception after release
public void test1_2SetStrengthAfterRelease() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
getVirtualizer(0);
mVirtualizer.release();
try {
@@ -158,6 +174,10 @@
//Test case 2.0: test setEnabled() and getEnabled() in valid state
public void test2_0SetEnabledGetEnabled() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
getVirtualizer(0);
try {
mVirtualizer.setEnabled(true);
@@ -173,6 +193,10 @@
//Test case 2.1: test setEnabled() throws exception after release
public void test2_1SetEnabledAfterRelease() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
getVirtualizer(0);
mVirtualizer.release();
try {
@@ -190,6 +214,10 @@
//Test case 3.0: test control status listener
public void test3_0ControlStatusListener() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
synchronized(mLock) {
mHasControl = true;
mInitialized = false;
@@ -212,6 +240,10 @@
//Test case 3.1: test enable status listener
public void test3_1EnableStatusListener() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
synchronized(mLock) {
mInitialized = false;
createListenerLooper(false, true, false);
@@ -236,6 +268,10 @@
//Test case 3.2: test parameter changed listener
public void test3_2ParameterChangedListener() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+
synchronized(mLock) {
mInitialized = false;
createListenerLooper(false, false, true);
@@ -263,6 +299,10 @@
// private methods
//----------------------------------
+ private boolean isVirtualizerAvailable() {
+ return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_VIRTUALIZER);
+ }
+
private void getVirtualizer(int session) {
if (mVirtualizer == null || session != mSession) {
if (session != mSession && mVirtualizer != null) {
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
index 5b34b3d..48b816c 100644
--- a/tests/tests/nativemedia/sl/Android.mk
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -10,6 +10,9 @@
LOCAL_MODULE := $(test_executable)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_C_INCLUDES := \
bionic \
diff --git a/tests/tests/nativemedia/xa/Android.mk b/tests/tests/nativemedia/xa/Android.mk
index 6995bc0..ace315a 100644
--- a/tests/tests/nativemedia/xa/Android.mk
+++ b/tests/tests/nativemedia/xa/Android.mk
@@ -10,6 +10,9 @@
LOCAL_MODULE:= $(test_executable)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_C_INCLUDES := \
bionic \
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 7faea64..d8df064 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -28,6 +28,7 @@
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.TxPacketCountListener;
import android.net.wifi.WifiManager.WifiLock;
+import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -36,6 +37,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class WifiManagerTest extends AndroidTestCase {
@@ -46,7 +48,7 @@
private WifiManager mWifiManager;
private WifiLock mWifiLock;
private static MySync mMySync;
- private List<ScanResult> mScanResult = null;
+ private List<ScanResult> mScanResults = null;
private NetworkInfo mNetworkInfo;
// Please refer to WifiManager
@@ -66,6 +68,10 @@
private static final int TIMEOUT_MSEC = 6000;
private static final int WAIT_MSEC = 60;
private static final int DURATION = 10000;
+ private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000;
+ private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000;
+ private static final int WIFI_SCAN_TEST_ITERATIONS = 5;
+
private IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -74,9 +80,9 @@
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
synchronized (mMySync) {
if (mWifiManager.getScanResults() != null) {
- mScanResult = mWifiManager.getScanResults();
+ mScanResults = mWifiManager.getScanResults();
mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE;
- mScanResult = mWifiManager.getScanResults();
+ mScanResults = mWifiManager.getScanResults();
mMySync.notifyAll();
}
}
@@ -261,6 +267,46 @@
}
/**
+ * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with
+ * {@link SystemClock#elapsedRealtime()} on device.<p>
+ * To run this test in cts-tradefed:
+ * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp
+ */
+ public void testWifiScanTimestamp() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ Log.d(TAG, "Skipping test as WiFi is not supported");
+ return;
+ }
+ if (!mWifiManager.isWifiEnabled()) {
+ setWifiEnabled(true);
+ }
+ // Scan multiple times to make sure scan timestamps increase with device timestamp.
+ for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) {
+ startScan();
+ // Make sure at least one AP is found.
+ assertFalse("empty scan results!", mScanResults.isEmpty());
+ long nowMillis = SystemClock.elapsedRealtime();
+ // Keep track of how many APs are fresh in one scan.
+ int numFreshAps = 0;
+ for (ScanResult result : mScanResults) {
+ long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp);
+ if (Math.abs(nowMillis - scanTimeMillis) < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) {
+ numFreshAps++;
+ }
+ }
+ // At least half of the APs in the scan should be fresh.
+ int numTotalAps = mScanResults.size();
+ String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: "
+ + numFreshAps;
+ assertTrue(msg, numFreshAps * 2 >= mScanResults.size());
+ if (i < WIFI_SCAN_TEST_ITERATIONS - 1) {
+ // Wait before running next iteration.
+ Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS);
+ }
+ }
+ }
+
+ /**
* test point of wifiManager NetWork:
* 1.add NetWork
* 2.update NetWork
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 08db484..26b07f1 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -18,8 +18,13 @@
import android.os.Build;
+import android.os.SystemProperties;
+
+import dalvik.system.VMRuntime;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;
@@ -27,59 +32,76 @@
public class BuildTest extends TestCase {
- private static final String RO_PRODUCT_CPU_ABI = "ro.product.cpu.abi";
-
- private static final String RO_PRODUCT_CPU_ABI2 = "ro.product.cpu.abi2";
+ private static final String RO_PRODUCT_CPU_ABILIST = "ro.product.cpu.abilist";
+ private static final String RO_PRODUCT_CPU_ABILIST32 = "ro.product.cpu.abilist32";
+ private static final String RO_PRODUCT_CPU_ABILIST64 = "ro.product.cpu.abilist64";
/** Tests that check the values of {@link Build#CPU_ABI} and {@link Build#CPU_ABI2}. */
- public void testCpuAbi() throws IOException {
- if (CpuFeatures.isArmCpu()) {
- assertArmCpuAbiConstants();
+ public void testCpuAbi() throws Exception {
+ testCpuAbiCommon();
+ if (VMRuntime.getRuntime().is64Bit()) {
+ testCpuAbi64();
+ } else {
+ testCpuAbi32();
}
}
- private void assertArmCpuAbiConstants() throws IOException {
- if (CpuFeatures.isArm7Compatible()) {
- String cpuAbi = getProperty(RO_PRODUCT_CPU_ABI);
- String cpuAbi2 = getProperty(RO_PRODUCT_CPU_ABI2);
- //if CPU_ABI is armv7, CPU_ABI2 is either of {armeabi, NULL}
- if (cpuAbi.equals(CpuFeatures.ARMEABI_V7)) {
- String message = "CPU is ARM v7 compatible, so "
- + RO_PRODUCT_CPU_ABI + " must be set to " + CpuFeatures.ARMEABI_V7 + " and "
- + RO_PRODUCT_CPU_ABI2 + " must be set to " + CpuFeatures.ARMEABI + " or NULL";
- assertEquals(message, CpuFeatures.ARMEABI_V7, Build.CPU_ABI);
- if (cpuAbi2.equals(CpuFeatures.ARMEABI)){
- assertEquals(message, cpuAbi2, Build.CPU_ABI2);
- } else {
- assertNoPropertySet(message, RO_PRODUCT_CPU_ABI2);
- assertEquals(message, Build.UNKNOWN, Build.CPU_ABI2);
- }
- }
- //if CPU_ABI is x86, then CPU_ABI2 is either of {armeabi, armv7, NULL}
- else if (cpuAbi.equals(CpuFeatures.X86ABI)) {
- String message = "CPU is x86 but ARM v7 compatible, so "
- + RO_PRODUCT_CPU_ABI + " must be set to " + CpuFeatures.X86ABI + " and "
- + RO_PRODUCT_CPU_ABI2 + " must be set to " + CpuFeatures.ARMEABI + " or "
- + CpuFeatures.ARMEABI_V7 + " or NULL";
- assertEquals(message, CpuFeatures.X86ABI, Build.CPU_ABI);
- if (cpuAbi2.equals(CpuFeatures.ARMEABI_V7) || cpuAbi2.equals(CpuFeatures.ARMEABI))
- assertEquals(message, cpuAbi2, Build.CPU_ABI2);
- else {
- assertNoPropertySet(message, RO_PRODUCT_CPU_ABI2);
- assertEquals(message, Build.UNKNOWN, Build.CPU_ABI2);
- }
- }
+ private void testCpuAbiCommon() throws Exception {
+ // The build property must match Build.SUPPORTED_ABIS exactly.
+ final String[] abiListProperty = getStringList(RO_PRODUCT_CPU_ABILIST);
+ assertEquals(Arrays.toString(abiListProperty), Arrays.toString(Build.SUPPORTED_ABIS));
+
+ List<String> abiList = Arrays.asList(abiListProperty);
+
+ // Every device must support at least one 32 bit ABI.
+ assertTrue(Build.SUPPORTED_32_BIT_ABIS.length > 0);
+
+ // Every supported 32 bit ABI must be present in Build.SUPPORTED_ABIS.
+ for (String abi : Build.SUPPORTED_32_BIT_ABIS) {
+ assertTrue(abiList.contains(abi));
+ assertFalse(VMRuntime.is64BitAbi(abi));
}
- else {
- String message = "CPU is not ARM v7 compatible. "
- + RO_PRODUCT_CPU_ABI + " must be set to " + CpuFeatures.ARMEABI + " and "
- + RO_PRODUCT_CPU_ABI2 + " must not be set.";
- assertProperty(message, RO_PRODUCT_CPU_ABI, CpuFeatures.ARMEABI);
- assertNoPropertySet(message, RO_PRODUCT_CPU_ABI2);
- assertEquals(message, CpuFeatures.ARMEABI, Build.CPU_ABI);
- assertEquals(message, Build.UNKNOWN, Build.CPU_ABI2);
+
+ // Every supported 64 bit ABI must be present in Build.SUPPORTED_ABIS.
+ for (String abi : Build.SUPPORTED_64_BIT_ABIS) {
+ assertTrue(abiList.contains(abi));
+ assertTrue(VMRuntime.is64BitAbi(abi));
+ }
+
+ // Build.CPU_ABI and Build.CPU_ABI2 must be present in Build.SUPPORTED_ABIS.
+ assertTrue(abiList.contains(Build.CPU_ABI));
+ if (!Build.CPU_ABI2.isEmpty()) {
+ assertTrue(abiList.contains(Build.CPU_ABI2));
}
}
+
+ private void testCpuAbi32() throws Exception {
+ List<String> abi32 = Arrays.asList(Build.SUPPORTED_32_BIT_ABIS);
+ assertTrue(abi32.contains(Build.CPU_ABI));
+
+ if (!Build.CPU_ABI2.isEmpty()) {
+ assertTrue(abi32.contains(Build.CPU_ABI2));
+ }
+ }
+
+ private void testCpuAbi64() {
+ List<String> abi64 = Arrays.asList(Build.SUPPORTED_64_BIT_ABIS);
+ assertTrue(abi64.contains(Build.CPU_ABI));
+
+ if (!Build.CPU_ABI2.isEmpty()) {
+ assertTrue(abi64.contains(Build.CPU_ABI2));
+ }
+ }
+
+ private String[] getStringList(String property) throws IOException {
+ String value = getProperty(property);
+ if (value.isEmpty()) {
+ return new String[0];
+ } else {
+ return value.split(",");
+ }
+ }
+
/**
* @param property name passed to getprop
*/
diff --git a/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java b/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java
index 225c623..ee1b027 100644
--- a/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java
+++ b/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java
@@ -337,39 +337,50 @@
continue;
}
- // Get the context via attr/current
- String context = new Scanner(new File(f, "attr/current")).next();
- context = context.trim();
-
- // Get the vSize, item #23 from the stat file
- String x = new Scanner(new File(f, "stat")).nextLine();
- long vSize = getVsizeFromStat(x);
-
- StringBuilder sb = new StringBuilder();
- Scanner tmp = new Scanner(new File(f, "cmdline"));
-
- // Java's scanner tends to return oddly when handling
- // long binary blobs. Probably some caching optimization.
- while (tmp.hasNext()) {
- sb.append(tmp.next().replace('\0', ' '));
+ try {
+ ProcessDetails p = getProcessDetails(pid, f);
+ ArrayList<ProcessDetails> l = map.get(p.label);
+ if (l == null) {
+ l = new ArrayList<ProcessDetails>();
+ map.put(p.label, l);
+ }
+ l.add(p);
+ } catch (FileNotFoundException e) {
+ // sometimes processes go away while the test is running.
+ // Don't freak out if this happens
}
-
- // At this point we build up a valid proctitle, then split
- // on whitespace to get the left portion. Which is either
- // package name or process executable path. This avoids
- // the comm 16 char width limitation and is limited to PAGE_SIZE
- String cmdline = sb.toString().trim();
- cmdline = cmdline.split("\\s+")[0];
-
- ProcessDetails p = new ProcessDetails(cmdline, context, vSize, pid);
- ArrayList<ProcessDetails> l = map.get(context);
- if (l == null) {
- l = new ArrayList<ProcessDetails>();
- map.put(context, l);
- }
- l.add(p);
}
return map;
}
+
+ private static ProcessDetails getProcessDetails(int pid, File f) throws FileNotFoundException {
+ // Get the context via attr/current
+ String context = new Scanner(new File(f, "attr/current")).next();
+ context = context.trim();
+
+ // Get the vSize, item #23 from the stat file
+ String x = new Scanner(new File(f, "stat")).nextLine();
+ long vSize = getVsizeFromStat(x);
+
+ StringBuilder sb = new StringBuilder();
+ Scanner tmp = new Scanner(new File(f, "cmdline"));
+
+ // Java's scanner tends to return oddly when handling
+ // long binary blobs. Probably some caching optimization.
+ while (tmp.hasNext()) {
+ sb.append(tmp.next().replace('\0', ' '));
+ }
+ tmp.close();
+
+ // At this point we build up a valid proctitle, then split
+ // on whitespace to get the left portion. Which is either
+ // package name or process executable path. This avoids
+ // the comm 16 char width limitation and is limited to PAGE_SIZE
+ String cmdline = sb.toString().trim();
+ cmdline = cmdline.split("\\s+")[0];
+
+ return new ProcessDetails(cmdline, context, vSize, pid);
+ }
+
}
}
diff --git a/tests/tests/uirendering/res/drawable-nodpi/black1.png b/tests/tests/uirendering/res/drawable-nodpi/black1.png
new file mode 100644
index 0000000..3487ced
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/black1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
new file mode 100644
index 0000000..8fd3b50
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/bold1.png b/tests/tests/uirendering/res/drawable-nodpi/bold1.png
new file mode 100644
index 0000000..199cccc
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/bold1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
new file mode 100644
index 0000000..985635e
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensed1.png b/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
new file mode 100644
index 0000000..6889a3a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
new file mode 100644
index 0000000..9554dee
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
new file mode 100644
index 0000000..0483355
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
new file mode 100644
index 0000000..6584147
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
new file mode 100644
index 0000000..49d01ac
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
new file mode 100644
index 0000000..6fe4a76
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/hello1.png b/tests/tests/uirendering/res/drawable-nodpi/hello1.png
new file mode 100644
index 0000000..7a4be5a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/hello1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/italic1.png b/tests/tests/uirendering/res/drawable-nodpi/italic1.png
new file mode 100644
index 0000000..a5f9ef2
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/italic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/light1.png b/tests/tests/uirendering/res/drawable-nodpi/light1.png
new file mode 100644
index 0000000..dfa59da
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/light1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
new file mode 100644
index 0000000..283ddc4
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/medium1.png b/tests/tests/uirendering/res/drawable-nodpi/medium1.png
new file mode 100644
index 0000000..e615186
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/medium1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
new file mode 100644
index 0000000..3e15fc8
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/thin1.png b/tests/tests/uirendering/res/drawable-nodpi/thin1.png
new file mode 100644
index 0000000..9637262
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/thin1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
new file mode 100644
index 0000000..0afbb9a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
new file mode 100644
index 0000000..e7ed7ac
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 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 android.uirendering.cts.testclasses;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uirendering.cts.bitmapcomparers.BitmapComparer;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+
+import com.android.cts.uirendering.R;
+
+public class FontRenderingTests extends ActivityTestBase {
+ // Threshold is barely loose enough for differences between sw and hw renderers
+ static double MSSIM_THRESHOLD = 0.91;
+
+ private final BitmapComparer mFuzzyComparer = new MSSIMComparer(MSSIM_THRESHOLD);
+
+ // Representative characters including some from Unicode 7
+ private final String mTestString1 = "Hamburg \u20bd";
+ private final String mTestString2 = "\u20b9\u0186\u0254\u1e24\u1e43";
+
+ private void fontTestBody(final Typeface typeface, int id) {
+ Bitmap goldenBitmap = BitmapFactory.decodeResource(getActivity().getResources(), id);
+ createTest()
+ .addCanvasClient(new CanvasClient() {
+ @Override
+ public void draw(Canvas canvas, int width, int height) {
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setColor(Color.BLACK);
+ p.setTextSize(30);
+ p.setTypeface(typeface);
+ canvas.drawText(mTestString1, 10, 60, p);
+ canvas.drawText(mTestString2, 10, 100, p);
+ }
+ })
+ .runWithVerifier(new GoldenImageVerifier(goldenBitmap, mFuzzyComparer));
+ }
+
+ @SmallTest
+ public void testDefaultFont() {
+ Typeface tf = Typeface.create("sans-serif", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.hello1);
+ }
+
+ @SmallTest
+ public void testBoldFont() {
+ Typeface tf = Typeface.create("sans-serif", Typeface.BOLD);
+ fontTestBody(tf, R.drawable.bold1);
+ }
+
+ @SmallTest
+ public void testItalicFont() {
+ Typeface tf = Typeface.create("sans-serif", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.italic1);
+ }
+
+ @SmallTest
+ public void testBoldItalicFont() {
+ Typeface tf = Typeface.create("sans-serif", Typeface.BOLD | Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.bolditalic1);
+ }
+
+ @SmallTest
+ public void testMediumFont() {
+ Typeface tf = Typeface.create("sans-serif-medium", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.medium1);
+ }
+
+ @SmallTest
+ public void testMediumBoldFont() {
+ // bold attribute on medium base font = black
+ Typeface tf = Typeface.create("sans-serif-medium", Typeface.BOLD);
+ fontTestBody(tf, R.drawable.black1);
+ }
+
+ @SmallTest
+ public void testMediumItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-medium", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.mediumitalic1);
+ }
+
+ @SmallTest
+ public void testMediumBoldItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-medium", Typeface.BOLD | Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.blackitalic1);
+ }
+
+ @SmallTest
+ public void testLightFont() {
+ Typeface tf = Typeface.create("sans-serif-light", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.light1);
+ }
+
+ @SmallTest
+ public void testLightBoldFont() {
+ // bold attribute on light base font = medium
+ Typeface tf = Typeface.create("sans-serif-light", Typeface.BOLD);
+ fontTestBody(tf, R.drawable.medium1);
+ }
+
+ @SmallTest
+ public void testLightItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-light", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.lightitalic1);
+ }
+
+ @SmallTest
+ public void testLightBoldItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-light", Typeface.BOLD | Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.mediumitalic1);
+ }
+
+ @SmallTest
+ public void testThinFont() {
+ Typeface tf = Typeface.create("sans-serif-thin", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.thin1);
+ }
+
+ @SmallTest
+ public void testThinBoldFont() {
+ // bold attribute on thin base font = normal
+ Typeface tf = Typeface.create("sans-serif-thin", Typeface.BOLD);
+ fontTestBody(tf, R.drawable.hello1);
+ }
+
+ @SmallTest
+ public void testThinItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-thin", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.thinitalic1);
+ }
+
+ @SmallTest
+ public void testThinBoldItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-thin", Typeface.BOLD | Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.italic1);
+ }
+
+ @SmallTest
+ public void testBlackFont() {
+ Typeface tf = Typeface.create("sans-serif-black", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.black1);
+ }
+
+ @SmallTest
+ public void testBlackBoldFont() {
+ // bold attribute on black base font = black
+ Typeface tf = Typeface.create("sans-serif-black", Typeface.BOLD);
+ fontTestBody(tf, R.drawable.black1);
+ }
+
+ @SmallTest
+ public void testBlackItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-black", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.blackitalic1);
+ }
+
+ @SmallTest
+ public void testBlackBoldItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-black", Typeface.BOLD | Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.blackitalic1);
+ }
+
+ /* condensed fonts */
+
+ @SmallTest
+ public void testCondensedFont() {
+ Typeface tf = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.condensed1);
+ }
+
+ @SmallTest
+ public void testCondensedBoldFont() {
+ Typeface tf = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+ fontTestBody(tf, R.drawable.condensedbold1);
+ }
+
+ @SmallTest
+ public void testCondensedItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-condensed", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.condenseditalic1);
+ }
+
+ @SmallTest
+ public void testCondensedBoldItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-condensed", Typeface.BOLD | Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.condensedbolditalic1);
+ }
+
+ @SmallTest
+ public void testCondensedLightFont() {
+ Typeface tf = Typeface.create("sans-serif-condensed-light", Typeface.NORMAL);
+ fontTestBody(tf, R.drawable.condensedlight1);
+ }
+
+ @SmallTest
+ public void testCondensedLightItalicFont() {
+ Typeface tf = Typeface.create("sans-serif-condensed-light", Typeface.ITALIC);
+ fontTestBody(tf, R.drawable.condensedlightitalic1);
+ }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index 9f9aa41..052b251 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -185,7 +185,8 @@
TEST_WIDTH, TEST_HEIGHT);
boolean success = bitmapVerifier.verify(mSoftwareArray, 0, TEST_WIDTH, TEST_WIDTH, TEST_HEIGHT);
if (!success) {
- BitmapDumper.dumpBitmap(bitmap, getName(), this.getClass().getSimpleName());
+ Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, TEST_WIDTH, TEST_HEIGHT);
+ BitmapDumper.dumpBitmap(croppedBitmap, getName(), this.getClass().getSimpleName());
BitmapDumper.dumpBitmap(bitmapVerifier.getDifferenceBitmap(), getName() + "_verifier",
this.getClass().getSimpleName());
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
index be680d9..41e255b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
@@ -84,9 +84,10 @@
int[] visualizerArray = differenceVisualizer.getDifferences(idealArray, testedArray);
visualizerBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
visualizerBitmap.setPixels(visualizerArray, 0, width, 0, 0, width, height);
+ Bitmap croppedBitmap = Bitmap.createBitmap(testedBitmap, 0, 0, width, height);
saveFile(className, testName, IDEAL_RENDERING_FILE_NAME, idealBitmap);
- saveFile(className, testName, TESTED_RENDERING_FILE_NAME, testedBitmap);
+ saveFile(className, testName, TESTED_RENDERING_FILE_NAME, croppedBitmap);
saveFile(className, testName, VISUALIZER_RENDERING_FILE_NAME, visualizerBitmap);
}
diff --git a/tests/tests/widget/res/layout/popupwindow.xml b/tests/tests/widget/res/layout/popupwindow.xml
index 2508115..f93f965 100644
--- a/tests/tests/widget/res/layout/popupwindow.xml
+++ b/tests/tests/widget/res/layout/popupwindow.xml
@@ -14,37 +14,36 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <TextView android:id="@+id/anchor_upper"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_view_hint" />
+ <View android:id="@+id/anchor_upper"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="#f00" />
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
+ <View android:id="@+id/anchor_lower"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:background="#0f0" />
- <TextView android:id="@+id/anchor_middle_left"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:text="@string/text_view_hint"
- android:layout_weight="1"/>
+ <View android:id="@+id/anchor_middle_left"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:background="#00f" />
- <TextView android:id="@+id/anchor_middle_right"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:text="@string/text_view_hint"
- android:layout_weight="1"/>
+ <View android:id="@+id/anchor_middle_right"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="#ff0" />
- </LinearLayout>
-
- <TextView android:id="@+id/anchor_lower"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_view_hint" />
-
-</LinearLayout>
+</RelativeLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 4a14d2b..e1742c8 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -25,6 +25,7 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Debug;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
@@ -580,7 +581,8 @@
assertEquals(50, mPopupWindow.getHeight());
mPopupWindow.getContentView().getLocationOnScreen(viewXY);
- // the position should be changed
+
+ // The popup should appear below and to right with an offset.
assertEquals(anchorXY[0] + 20 + viewInWindowOff[0], viewXY[0]);
assertEquals(anchorXY[1] + anchorView.getHeight() + 50 + viewInWindowOff[1], viewXY[1]);
@@ -597,14 +599,15 @@
assertEquals(50, mPopupWindow.getHeight());
mPopupWindow.getContentView().getLocationOnScreen(viewXY);
- // the position should be changed
+
+ // The popup should appear below and to right with an offset.
assertEquals(anchorXY[0] + 10 + viewInWindowOff[0], viewXY[0]);
assertEquals(anchorXY[1] + anchorView.getHeight() + 50 + viewInWindowOff[1], viewXY[1]);
- final View anthoterView = mActivity.findViewById(R.id.anchor_middle_right);
+ final View anotherView = mActivity.findViewById(R.id.anchor_middle_left);
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
- mPopupWindow.update(anthoterView, 0, 0, 60, 60);
+ mPopupWindow.update(anotherView, 0, 0, 60, 60);
}
});
mInstrumentation.waitForIdleSync();
@@ -614,11 +617,12 @@
assertEquals(60, mPopupWindow.getHeight());
int[] newXY = new int[2];
- anthoterView.getLocationOnScreen(newXY);
+ anotherView.getLocationOnScreen(newXY);
mPopupWindow.getContentView().getLocationOnScreen(viewXY);
- // the position should be changed
+
+ // The popup should appear below and to the right.
assertEquals(newXY[0] + viewInWindowOff[0], viewXY[0]);
- assertEquals(newXY[1] + anthoterView.getHeight() + viewInWindowOff[1], viewXY[1]);
+ assertEquals(newXY[1] + anotherView.getHeight() + viewInWindowOff[1], viewXY[1]);
dismissPopup();
}
@@ -815,8 +819,7 @@
}
private View createPopupContent() {
- TextView popupView = new TextView(mActivity);
- popupView.setText("Popup");
+ View popupView = new View(mActivity);
popupView.setLayoutParams(new ViewGroup.LayoutParams(50, 50));
popupView.setBackgroundColor(Color.WHITE);
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
index 1680cae..833bf69 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
@@ -205,7 +205,8 @@
String className = nameCollector.toString();
nameCollector.append('#').append(test.getName());
writer.append("<Test name=\"").append(test.getName()).append("\"");
- String abis = getSupportedAbis(mUnsupportedAbis, mArchitecture, className).toString();
+ String abis = getSupportedAbis(mUnsupportedAbis, mArchitecture,
+ className, nameCollector.toString()).toString();
writer.append(" abis=\"" + abis.substring(1, abis.length() - 1) + "\"");
if (isKnownFailure(mKnownFailures, nameCollector.toString())) {
writer.append(" expectation=\"failure\"");
@@ -232,23 +233,36 @@
// Returns the list of ABIs supported by this TestCase on this architecture.
public static Set<String> getSupportedAbis(ExpectationStore expectationStore,
- String architecture, String className) {
+ String architecture, String className, String testName) {
Set<String> supportedAbis = AbiUtils.getAbisForArch(architecture);
- Expectation e = (expectationStore == null) ? null : expectationStore.get(className);
- if (e != null && !e.getDescription().isEmpty()) {
- // Description should be written in the form "blah blah: abi1, abi2..."
- String description = e.getDescription().split(":")[1];
- String[] unsupportedAbis = description.split(",");
- for (String a : unsupportedAbis) {
- String abi = a.trim();
- if (!AbiUtils.isAbiSupportedByCts(abi)) {
- throw new RuntimeException(
- String.format("Unrecognised ABI %s in %s", abi, e.getDescription()));
- }
- supportedAbis.remove(abi);
- }
+ if (expectationStore == null) {
+ return supportedAbis;
}
+
+ removeUnsupportedAbis(expectationStore.get(className), supportedAbis);
+ removeUnsupportedAbis(expectationStore.get(testName), supportedAbis);
return supportedAbis;
}
+ public static void removeUnsupportedAbis(Expectation expectation, Set<String> supportedAbis) {
+ if (expectation == null) {
+ return;
+ }
+
+ String description = expectation.getDescription();
+ if (description.isEmpty()) {
+ return;
+ }
+
+ String[] unsupportedAbis = description.split(":")[1].split(",");
+ for (String a : unsupportedAbis) {
+ String abi = a.trim();
+ if (!AbiUtils.isAbiSupportedByCts(abi)) {
+ throw new RuntimeException(
+ String.format("Unrecognised ABI %s in %s", abi, description));
+ }
+ supportedAbis.remove(abi);
+ }
+ }
+
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
index 61b4b43..0940355 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
@@ -33,7 +33,7 @@
private final String mSuiteName = "CTS";
/** The root location of the extracted CTS package */
private final File mRootDir;
- /** the {@link CTS_DIR_NAME} directory */
+ /** the {@link #CTS_DIR_NAME} directory */
private final File mCtsDir;
/**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 8224481..08e9a0b 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -33,7 +33,6 @@
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.LogFileSaver;
import com.android.tradefed.result.TestSummary;
-import com.android.tradefed.util.AbiFormatter;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.StreamUtil;
@@ -226,6 +225,7 @@
mIsDeviceInfoRun = DeviceInfoCollector.IDS.contains(id);
if (!mIsDeviceInfoRun) {
mCurrentPkgResult = mResults.getOrCreatePackage(id);
+ mCurrentPkgResult.setDeviceSerial(mDeviceSerial);
}
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 6d617ea..7aed84d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -762,15 +762,26 @@
*/
private void installPrerequisiteApks(Collection<String> prerequisiteApks)
throws DeviceNotAvailableException {
+ Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Installing prerequisites");
+ Set<String> supportedAbiSet = getAbis();
for (String apkName : prerequisiteApks) {
try {
File apkFile = mCtsBuild.getTestApp(apkName);
- String errorCode = null;
- String abi = AbiFormatter.getDefaultAbi(getDevice(), mForceAbi);
- String[] options = {AbiUtils.createAbiFlag(abi)};
- errorCode = getDevice().installPackage(apkFile, true, options);
- if (errorCode != null) {
- CLog.e("Failed to install %s. Reason: %s", apkName, errorCode);
+ // As a workaround for multi arch support, try to install the APK
+ // for all device supported ABIs. This will generate warning messages
+ // until the above FIXME is resolved.
+ int installFailCount = 0;
+ for (String abi : supportedAbiSet) {
+ String[] options = {AbiUtils.createAbiFlag(abi)};
+ String errorCode = getDevice().installPackage(apkFile, true, options);
+ if (errorCode != null) {
+ installFailCount++;
+ CLog.w("Failed to install %s. Reason: %s", apkName, errorCode);
+ }
+
+ }
+ if (installFailCount >= supportedAbiSet.size()) {
+ CLog.e("Failed to install %s. See warning messages.", apkName);
}
} catch (FileNotFoundException e) {
CLog.e("Could not find test apk %s", apkName);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
index 9bfe151..6c2ed65 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
@@ -49,9 +49,9 @@
private CtsBuildHelper mCtsBuild;
private ITestDevice mDevice;
private IAbi mAbi;
+ private String mExeName;
private final String mPackageName;
- private final String mExeName;
public GeeTest(String packageName, String exeName) {
mPackageName = packageName;
@@ -63,6 +63,7 @@
*/
public void setAbi(IAbi abi) {
mAbi = abi;
+ mExeName += mAbi.getBitness();
}
@Override
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 4a1b2f3..6a80255 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -158,7 +158,6 @@
# CTS Stable plan
plan = tools.TestPlan(packages)
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-stable')
@@ -167,7 +166,6 @@
plan = tools.TestPlan(packages)
plan.Exclude('.*')
plan.Include(r'com\.android\.cts\.browserbench')
- plan.Include(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.Include(package+'$')
plan.IncludeTests(package, test_list)
@@ -183,7 +181,6 @@
for package, test_list in small_tests.iteritems():
plan.Include(package+'$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-kitkat-small')
@@ -194,7 +191,6 @@
for package, test_list in medium_tests.iteritems():
plan.Include(package+'$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-kitkat-medium')
@@ -204,7 +200,6 @@
plan.Exclude('.*')
plan.Include(r'android\.hardware$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-hardware')
@@ -214,7 +209,6 @@
plan.Exclude('.*')
plan.Include(r'android\.media$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-media')
@@ -224,7 +218,6 @@
plan.Exclude('.*')
plan.Include(r'android\.mediastress$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-mediastress')
@@ -235,7 +228,6 @@
for package, test_list in new_test_packages.iteritems():
plan.Include(package+'$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-l-tests')
@@ -252,7 +244,6 @@
plan.Exclude(r'android\.media$')
plan.Exclude(r'android\.mediastress$')
plan.Exclude(r'com\.android\.cts\.browserbench')
- plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-staging')
@@ -261,6 +252,12 @@
plan.Exclude('.*')
plan.Include(r'android\.core\.tests\.libcore\.')
plan.Include(r'android\.jdwp')
+ for package, test_list in small_tests.iteritems():
+ plan.Exclude(package+'$')
+ for package, test_list in medium_tests.iteritems():
+ plan.Exclude(package+'$')
+ for package, tests_list in new_test_packages.iteritems():
+ plan.Exclude(package+'$')
self.__WritePlan(plan, 'CTS-ART')
plan = tools.TestPlan(packages)
@@ -359,7 +356,6 @@
def BuildCtsVettedNewPackagesList():
""" Construct a defaultdict that maps package names that is vetted for L. """
return {
- 'android.appwidget' : [],
'android.core.tests.libcore.package.harmony_annotation' : [],
'android.core.tests.libcore.package.harmony_beans' : [],
'android.core.tests.libcore.package.harmony_java_io' : [],
@@ -368,6 +364,7 @@
'android.core.tests.libcore.package.harmony_java_net' : [],
'android.core.tests.libcore.package.harmony_java_nio' : [],
'android.core.tests.libcore.package.harmony_java_util' : [],
+ 'android.core.tests.libcore.package.harmony_java_text' : [],
'android.core.tests.libcore.package.harmony_javax_security' : [],
'android.core.tests.libcore.package.harmony_logging' : [],
'android.core.tests.libcore.package.harmony_prefs' : [],
@@ -384,11 +381,12 @@
'android.tv' : [],
'android.uiautomation' : [],
'android.uirendering' : [],
- 'android.webgl' : []}
+ 'android.webgl' : [],
+ 'com.drawelements.deqp.gles31' : []}
def BuildCtsFlakyTestList():
""" Construct a defaultdict that maps package name to a list of tests
- that are known to be flaky. """
+ that are known to be flaky in the lab or not passing on userdebug builds. """
return {
'android.app' : [
'cts.ActivityManagerTest#testIsRunningInTestHarness',],
@@ -423,7 +421,11 @@
'cts.SELinuxDomainTest#testSuDomain',
'cts.SELinuxHostTest#testAllEnforcing',],
'android.webkit' : [
- 'cts.WebViewClientTest#testOnUnhandledKeyEvent',]}
+ 'cts.WebViewClientTest#testOnUnhandledKeyEvent',],
+ 'com.android.cts.filesystemperf' : [
+ 'RandomRWTest#testRandomRead',
+ 'RandomRWTest#testRandomUpdate',],
+ '' : []}
def LogGenerateDescription(name):
print 'Generating test description for package %s' % name