Merge "Fix bug in general reduction test case (fz3 kernel) exposed by multithreading." into nyc-dev
diff --git a/OldCtsTestCaseList.mk b/OldCtsTestCaseList.mk
index 45a25f9..2e7de5e 100644
--- a/OldCtsTestCaseList.mk
+++ b/OldCtsTestCaseList.mk
@@ -76,6 +76,7 @@
CtsUnaffiliatedAccountAuthenticators
cts_support_packages := \
+ CtsAbiOverrideTestApp \
CtsAccountManagementDevicePolicyApp \
CtsAlarmClockService \
CtsAppRestrictionsManagingApp \
@@ -161,6 +162,7 @@
CtsCarTestCases \
CtsContentTestCases \
CtsDatabaseTestCases \
+ CtsDeviceAdminUninstallerTestCases \
CtsDisplayTestCases \
CtsDpiTestCases \
CtsDpiTestCases2 \
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index cf3d55a..79e8a36 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -29,6 +29,7 @@
android-support-v4 \
compatibility-common-util-devicesidelib \
cts-sensors-tests \
+ cts-location-tests \
ctstestrunner \
apache-commons-math \
androidplot \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 107b0eb..157b54f 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -437,6 +437,50 @@
<meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
</activity>
+ <activity android:name=".location.GnssMeasurementRegistrationTestsActivity"
+ android:label="@string/location_gnss_reg_test"
+ android:screenOrientation="locked">
+ <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_hardware"/>
+ <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+ </activity>
+
+ <activity android:name=".location.GnssMeasurementValuesTestsActivity"
+ android:label="@string/location_gnss_value_test"
+ android:screenOrientation="locked">
+ <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_hardware"/>
+ <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+ </activity>
+
+ <activity android:name=".location.GnssMeasurementWhenNoLocationTestsActivity"
+ android:label="@string/location_gnss_measure_no_location_test"
+ android:screenOrientation="locked">
+ <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_hardware"/>
+ <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+ </activity>
+
+ <activity android:name=".location.GnssNavigationMessageTestsActivity"
+ android:label="@string/location_gnss_nav_msg_test"
+ android:screenOrientation="locked">
+ <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_hardware"/>
+ <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+ </activity>
+
<activity android:name=".location.LocationListenerActivity"
android:label="@string/location_listener_activity"
android:configChanges="keyboardHidden|orientation|screenSize">
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index 591d3db..187e8d2 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -14,6 +14,14 @@
public <methods>;
}
+# ensure we keep public Gnss Measurement test methods, these are needed at runtime
+-keepclassmembers class * extends com.android.cts.verifier.location.BaseGnssTestActivity {
+ public <methods>;
+}
+-keepclassmembers class * extends android.location.cts.GnssTestCase {
+ public <methods>;
+}
+
-keepclasseswithmembers class * extends com.android.cts.verifier.location.LocationModeTestActivity
# keep mockito methods
@@ -34,3 +42,4 @@
-dontwarn com.android.okhttp.**
-dontwarn org.opencv.**
-dontwarn android.support.test.internal.runner.hidden.ExposedInstrumentationApi
+
diff --git a/apps/CtsVerifier/res/layout-land/gnss_test.xml b/apps/CtsVerifier/res/layout-land/gnss_test.xml
new file mode 100644
index 0000000..c511d40
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-land/gnss_test.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout app:ctsv_layout_box="all"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <TextView android:id="@+id/text"
+ android:textSize="14sp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <ScrollView
+ android:id="@+id/log_scroll_view"
+ android:fillViewport="true"
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/log_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </ScrollView>
+
+ </LinearLayout>
+
+ <include layout="@layout/snsr_next_button" />
+
+ </LinearLayout>
+</com.android.cts.verifier.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout-port/gnss_test.xml b/apps/CtsVerifier/res/layout-port/gnss_test.xml
new file mode 100644
index 0000000..560133a
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/gnss_test.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout app:ctsv_layout_box="all"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <TextView android:id="@+id/text"
+ android:textSize="14sp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <ScrollView
+ android:id="@+id/log_scroll_view"
+ android:fillViewport="true"
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/log_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ </ScrollView>
+
+ </LinearLayout>
+
+ <include layout="@layout/snsr_next_button" />
+
+ </LinearLayout>
+</com.android.cts.verifier.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout-small/gnss_test.xml b/apps/CtsVerifier/res/layout-small/gnss_test.xml
new file mode 100644
index 0000000..5caea07
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-small/gnss_test.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ScrollView android:id="@+id/log_scroll_view"
+ app:ctsv_layout_box="all"
+ android:fillViewport="true"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent">
+
+ <TextView android:id="@+id/text"
+ android:textSize="14sp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <LinearLayout android:id="@+id/log_layout"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"/>
+
+ <include layout="@layout/snsr_next_button"/>
+ </LinearLayout>
+
+ </ScrollView>
+</com.android.cts.verifier.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 8712a5b..50e1bdf 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -417,6 +417,17 @@
and then press OK to run the automated tests.</string>
<string name="location_listener_activity">Location listener</string>
+ <!-- Strings for Location GNSS tests -->
+ <string name="location_gnss_measure_no_location_test">GNSS Measurement WhenNoLocation Test</string>
+ <string name="location_gnss_reg_test">GNSS Measurement Registration Test</string>
+ <string name="location_gnss_value_test">GNSS Measurement Values Test</string>
+ <string name="location_gnss_nav_msg_test">GNSS Navigation Message Test</string>
+ <string name="location_gnss_test_info">This test verifies basic GNSS behavior.
+ Make sure the device has line of sight to GNSS satellites
+ (for example, stationary on a windowsill. If needed, try again, outside, also with the
+ device stationary, and with at least some view of the sky.) and then press Next to run
+ the automated tests.</string>
+
<!-- Strings for net.ConnectivityScreenOffTestActivity -->
<string name="network_screen_off_test">Network Connectivity Screen Off Test</string>
<string name="network_screen_off_test_instructions">
@@ -2070,6 +2081,16 @@
Also, check that if you can download files from your phone to the desktop computer. The test is successful if the files from your phone are not and cannot be downloaded through USB.\n
Please mark the test accordingly.
</string>
+ <string name="device_owner_set_user_icon">Setting the user icon</string>
+ <string name="device_owner_set_user_icon_instruction">
+ This test verifies that the user icon can be set.\n
+ 1. Press the set user icon button.\n
+ 2. Press the go button to go to Settings.\n
+ 3a. If there is a \"users\" section in Settings, check that the icon of the user \"owner\" is the CtsVerifier one and mark this test accordingly.\n
+ 3b. If there is no \"users\" section, mark this test as passed.\n
+ </string>
+ <string name="device_owner_set_user_icon_button">Set user icon</string>
+
<string name="profile_owner_permission_lockdown_test_info">
<b>
Before proceeding, check if com.android.cts.permissionapp (aka CtsPermissionApp) is installed in work profile by going to Settings > Apps. If not, please install the app before proceeding.\n\n
@@ -2441,6 +2462,13 @@
Do you see the programs named \"Dummy Program\" and their descriptions
"Dummy Program Description" in the EPG?
</string>
+ <string name="tv_input_discover_test_trigger_setup">
+ Select the \"Launch setup\" button and verify if the bundled TV app shows the list of installed
+ TV inputs for setup.
+ </string>
+ <string name="tv_input_discover_test_verify_trigger_setup">
+ Do you see the \"CTS Verifier\" input in the list?
+ </string>
<string name="tv_parental_control_test">TV app parental controls test</string>
<string name="tv_parental_control_test_info">
@@ -2468,6 +2496,7 @@
<string name="tv_launch_tv_app">Launch TV app</string>
<string name="tv_launch_epg">Launch EPG</string>
+ <string name="tv_launch_setup">Launch setup</string>
<string name="tv_channel_not_found">
CtsVerifier channel is not set up. Please set up before proceeding.
</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementRegistrationTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementRegistrationTestsActivity.java
new file mode 100644
index 0000000..56755cc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementRegistrationTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssMeasurementRegistrationTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS Gnss Measurement tests.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssMeasurementRegistrationTestsActivity extends GnssCtsTestActivity {
+ public GnssMeasurementRegistrationTestsActivity() {
+ super(GnssMeasurementRegistrationTest.class);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementValuesTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementValuesTestsActivity.java
new file mode 100644
index 0000000..4bdbddf
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementValuesTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssMeasurementValuesTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS Gnss Measurement tests.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssMeasurementValuesTestsActivity extends GnssCtsTestActivity {
+ public GnssMeasurementValuesTestsActivity() {
+ super(GnssMeasurementValuesTest.class);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementWhenNoLocationTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementWhenNoLocationTestsActivity.java
new file mode 100644
index 0000000..1ee74c5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementWhenNoLocationTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssMeasurementWhenNoLocationTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS GnssMeasurementWhenNoLocationTest.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssMeasurementWhenNoLocationTestsActivity extends GnssCtsTestActivity {
+ public GnssMeasurementWhenNoLocationTestsActivity() {
+ super(GnssMeasurementWhenNoLocationTest.class);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssNavigationMessageTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssNavigationMessageTestsActivity.java
new file mode 100644
index 0000000..a4c9c93
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssNavigationMessageTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssNavigationMessageTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS GnssNavigationMessageTest.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssNavigationMessageTestsActivity extends GnssCtsTestActivity {
+ public GnssNavigationMessageTestsActivity() {
+ super(GnssNavigationMessageTest.class);
+ }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/BaseGnssTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/BaseGnssTestActivity.java
new file mode 100644
index 0000000..6c626fb
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/BaseGnssTestActivity.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestResult;
+import com.android.cts.verifier.location.reporting.GnssTestDetails;
+
+import junit.framework.Assert;
+
+import com.android.cts.verifier.PassFailButtons;
+
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.cts.helpers.ActivityResultMultiplexedLatch;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import android.test.AndroidTestCase;
+
+/**
+ * A base Activity that is used to build different methods to execute tests inside CtsVerifier.
+ * i.e. CTS tests, and semi-automated CtsVerifier tests.
+ *
+ * This class provides access to the following flow:
+ * Activity set up
+ * Execute tests (implemented by sub-classes)
+ * Activity clean up
+ *
+ * Currently the following class structure is available:
+ * - BaseGnssTestActivity : provides the platform to execute Gnss tests inside
+ * | CtsVerifier.
+ * |
+ * -- GnssCtsTestActivity : an activity that can be inherited from to wrap a CTS
+ * | Gnss test, and execute it inside CtsVerifier
+ * | these tests do not require any operator interaction
+ */
+public abstract class BaseGnssTestActivity extends PassFailButtons.Activity
+ implements View.OnClickListener, Runnable, IGnssTestStateContainer {
+ @Deprecated
+ protected static final String LOG_TAG = "GnssTest";
+
+ protected final Class mTestClass;
+
+ private final int mLayoutId;
+
+ private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
+ private final ActivityResultMultiplexedLatch mActivityResultMultiplexedLatch =
+ new ActivityResultMultiplexedLatch();
+ private final ArrayList<CountDownLatch> mWaitForUserLatches = new ArrayList<CountDownLatch>();
+
+ private ScrollView mLogScrollView;
+ private LinearLayout mLogLayout;
+ private Button mNextButton;
+ private Button mPassButton;
+ private Button mFailButton;
+ protected TextView mTextView;
+
+ /**
+ * Constructor to be used by subclasses.
+ *
+ * @param testClass The class that contains the tests. It is dependant on test executor
+ * implemented by subclasses.
+ */
+ protected BaseGnssTestActivity(Class<? extends AndroidTestCase> testClass) {
+ this(testClass, R.layout.gnss_test);
+ }
+
+ /**
+ * Constructor to be used by subclasses. It allows to provide a custom layout for the test UI.
+ *
+ * @param testClass The class that contains the tests. It is dependant on test executor
+ * implemented by subclasses.
+ * @param layoutId The Id of the layout to use for the test UI. The layout must contain all the
+ * elements in the base layout {@code R.layout.gnss_test}.
+ */
+ protected BaseGnssTestActivity(Class testClass, int layoutId) {
+ mTestClass = testClass;
+ mLayoutId = layoutId;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(mLayoutId);
+
+ mLogScrollView = (ScrollView) findViewById(R.id.log_scroll_view);
+ mLogLayout = (LinearLayout) findViewById(R.id.log_layout);
+ mNextButton = (Button) findViewById(R.id.next_button);
+ mNextButton.setOnClickListener(this);
+ mPassButton = (Button) findViewById(R.id.pass_button);
+ mFailButton = (Button) findViewById(R.id.fail_button);
+ mTextView = (TextView) findViewById(R.id.text);
+
+ mTextView.setText(R.string.location_gnss_test_info);
+
+ updateNextButton(false /*enabled*/);
+ mExecutorService.execute(this);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mExecutorService.shutdownNow();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onClick(View target) {
+ synchronized (mWaitForUserLatches) {
+ for (CountDownLatch latch : mWaitForUserLatches) {
+ latch.countDown();
+ }
+ mWaitForUserLatches.clear();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mActivityResultMultiplexedLatch.onActivityResult(requestCode, resultCode);
+ }
+
+ /**
+ * The main execution {@link Thread}.
+ *
+ * This function executes in a background thread, allowing the test run freely behind the
+ * scenes. It provides the following execution hooks:
+ * - Activity SetUp/CleanUp (not available in JUnit)
+ * - executeTests: to implement several execution engines
+ */
+ @Override
+ public void run() {
+ long startTimeNs = SystemClock.elapsedRealtimeNanos();
+ String testName = getTestClassName();
+
+ GnssTestDetails testDetails;
+ try {
+ testDetails = new GnssTestDetails(testName, GnssTestDetails.ResultCode.PASS);
+ } catch (Throwable e) {
+ testDetails = new GnssTestDetails(testName, "DeactivateFeatures", e);
+ }
+
+ GnssTestDetails.ResultCode resultCode = testDetails.getResultCode();
+ if (resultCode == GnssTestDetails.ResultCode.SKIPPED) {
+ // this is an invalid state at this point of the test setup
+ throw new IllegalStateException("Deactivation of features cannot skip the test.");
+ }
+ if (resultCode == GnssTestDetails.ResultCode.PASS) {
+ testDetails = executeActivityTests(testName);
+ }
+ }
+
+ /**
+ * A general set up routine. It executes only once before the first test case.
+ *
+ * NOTE: implementers must be aware of the interrupted status of the worker thread, and let
+ * {@link InterruptedException} propagate.
+ *
+ * @throws Throwable An exception that denotes the failure of set up. No tests will be executed.
+ */
+ protected void activitySetUp() throws Throwable {}
+
+ /**
+ * A general clean up routine. It executes upon successful execution of {@link #activitySetUp()}
+ * and after all the test cases.
+ *
+ * NOTE: implementers must be aware of the interrupted status of the worker thread, and handle
+ * it in two cases:
+ * - let {@link InterruptedException} propagate
+ * - if it is invoked with the interrupted status, prevent from showing any UI
+
+ * @throws Throwable An exception that will be logged and ignored, for ease of implementation
+ * by subclasses.
+ */
+ protected void activityCleanUp() throws Throwable {}
+
+ /**
+ * Performs the work of executing the tests.
+ * Sub-classes implementing different execution methods implement this method.
+ *
+ * @return A {@link GnssTestDetails} object containing information about the executed tests.
+ */
+ protected abstract GnssTestDetails executeTests() throws InterruptedException;
+
+ @Deprecated
+ protected void appendText(String text) {
+ TextAppender textAppender = new TextAppender(R.layout.snsr_instruction);
+ textAppender.setText(text);
+ textAppender.append();
+ }
+
+ @Deprecated
+ protected void clearText() {
+ this.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mLogLayout.removeAllViews();
+ }
+ });
+ }
+
+ /**
+ * Waits for the operator to acknowledge a requested action.
+ *
+ * @param waitMessageResId The action requested to the operator.
+ */
+ protected void waitForUser(int waitMessageResId) throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ synchronized (mWaitForUserLatches) {
+ mWaitForUserLatches.add(latch);
+ }
+
+ updateNextButton(true);
+ latch.await();
+ updateNextButton(false);
+ }
+
+ /**
+ * Waits for the operator to acknowledge to begin execution.
+ */
+ protected void waitForUserToBegin() throws InterruptedException {
+ waitForUser(R.string.snsr_wait_to_begin);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void waitForUserToContinue() throws InterruptedException {
+ waitForUser(R.string.snsr_wait_for_user);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int executeActivity(String action) throws InterruptedException {
+ return executeActivity(new Intent(action));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int executeActivity(Intent intent) throws InterruptedException {
+ ActivityResultMultiplexedLatch.Latch latch = mActivityResultMultiplexedLatch.bindThread();
+ startActivityForResult(intent, latch.getRequestCode());
+ return latch.await();
+ }
+
+ /**
+ * Plays a (default) sound as a notification for the operator.
+ */
+ protected void playSound() throws InterruptedException {
+ MediaPlayer player = MediaPlayer.create(this, Settings.System.DEFAULT_NOTIFICATION_URI);
+ if (player == null) {
+ Log.e(LOG_TAG, "MediaPlayer unavailable.");
+ return;
+ }
+ player.start();
+ try {
+ Thread.sleep(500);
+ } finally {
+ player.stop();
+ }
+ }
+
+ /**
+ * Makes the device vibrate for the given amount of time.
+ */
+ protected void vibrate(int timeInMs) {
+ Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(timeInMs);
+ }
+
+ /**
+ * Makes the device vibrate following the given pattern.
+ * See {@link Vibrator#vibrate(long[], int)} for more information.
+ */
+ protected void vibrate(long[] pattern) {
+ Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(pattern, -1);
+ }
+
+ protected String getTestClassName() {
+ if (mTestClass == null) {
+ return "<unknown>";
+ }
+ return mTestClass.getName();
+ }
+
+ protected void setLogScrollViewListener(View.OnTouchListener listener) {
+ mLogScrollView.setOnTouchListener(listener);
+ }
+
+ private void setTestResult(GnssTestDetails testDetails) {
+ // the name here, must be the Activity's name because it is what CtsVerifier expects
+ String name = super.getClass().getName();
+ //String summary = mTestLogger.getOverallSummary();
+ GnssTestDetails.ResultCode resultCode = testDetails.getResultCode();
+ switch(resultCode) {
+ case SKIPPED:
+ TestResult.setPassedResult(this, name, "");
+ break;
+ case PASS:
+ TestResult.setPassedResult(this, name, "");
+ break;
+ case FAIL:
+ TestResult.setFailedResult(this, name, "");
+ break;
+ case INTERRUPTED:
+ // do not set a result, just return so the test can complete
+ break;
+ default:
+ throw new IllegalStateException("Unknown ResultCode: " + resultCode);
+ }
+ }
+
+ private GnssTestDetails executeActivityTests(String testName) {
+ GnssTestDetails testDetails;
+ try {
+ activitySetUp();
+ testDetails = new GnssTestDetails(testName, GnssTestDetails.ResultCode.PASS);
+ } catch (Throwable e) {
+ testDetails = new GnssTestDetails(testName, "ActivitySetUp", e);
+ }
+
+ GnssTestDetails.ResultCode resultCode = testDetails.getResultCode();
+ if (resultCode == GnssTestDetails.ResultCode.PASS) {
+ // TODO: implement execution filters:
+ // - execute all tests and report results officially
+ // - execute single test or failed tests only
+ try {
+ testDetails = executeTests();
+ } catch (Throwable e) {
+ // we catch and continue because we have to guarantee a proper clean-up sequence
+ testDetails = new GnssTestDetails(testName, "TestExecution", e);
+ }
+ }
+
+ // clean-up executes for all states, even on SKIPPED and INTERRUPTED there might be some
+ // intermediate state that needs to be taken care of
+ try {
+ activityCleanUp();
+ } catch (Throwable e) {
+ testDetails = new GnssTestDetails(testName, "ActivityCleanUp", e);
+ }
+
+ return testDetails;
+ }
+
+ private void updateNextButton(final boolean enabled) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mNextButton.setEnabled(enabled);
+ }
+ });
+ }
+
+ private void enableTestResultButton(
+ final Button button,
+ final int textResId,
+ final GnssTestDetails testDetails) {
+ final View.OnClickListener listener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setTestResult(testDetails);
+ finish();
+ }
+ };
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mNextButton.setVisibility(View.GONE);
+ button.setText(textResId);
+ button.setOnClickListener(listener);
+ button.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+
+ private class ViewAppender {
+ protected final View mView;
+
+ public ViewAppender(View view) {
+ mView = view;
+ }
+
+ public void append() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mLogLayout.addView(mView);
+ mLogScrollView.post(new Runnable() {
+ @Override
+ public void run() {
+ mLogScrollView.fullScroll(View.FOCUS_DOWN);
+ }
+ });
+ }
+ });
+ }
+ }
+
+ private class TextAppender extends ViewAppender{
+ private final TextView mTextView;
+
+ public TextAppender(int textViewResId) {
+ super(getLayoutInflater().inflate(textViewResId, null /* viewGroup */));
+ mTextView = (TextView) mView;
+ }
+
+ public void setText(String text) {
+ mTextView.setText(text);
+ }
+
+ public void setText(int textResId) {
+ mTextView.setText(textResId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestActivity.java
new file mode 100644
index 0000000..db955ba
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestActivity.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import com.android.cts.verifier.R;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.internal.runners.SuiteMethod;
+import org.junit.runner.Computer;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.view.WindowManager;
+
+import java.lang.Override;
+import java.lang.Runnable;
+import java.util.concurrent.TimeUnit;
+
+import android.location.cts.GnssTestCase;
+import com.android.cts.verifier.location.reporting.GnssTestDetails;
+
+/**
+ * An Activity that allows Gnss CTS tests to be executed inside CtsVerifier.
+ *
+ * Sub-classes pass the test class as part of construction.
+ * One JUnit test class is executed per Activity, the test class can still be executed outside
+ * CtsVerifier.
+ */
+public class GnssCtsTestActivity extends BaseGnssTestActivity {
+
+ /**
+ * Constructor for a CTS test executor. It will execute a standalone CTS test class.
+ *
+ * @param testClass The test class to execute, it must be a subclass of {@link AndroidTestCase}.
+ */
+ protected GnssCtsTestActivity(Class<? extends GnssTestCase> testClass) {
+ super(testClass);
+ }
+
+ @Override
+ protected void activitySetUp() throws InterruptedException {
+ waitForUserToBegin();
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mTextView.setText("Running test... \n");
+ }
+ });
+ }
+
+ @Override
+ protected void activityCleanUp() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ }
+ });
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+ /**
+ * For reference on the implementation of this test executor see:
+ * android.support.test.runner.AndroidJUnitRunner
+ */
+ @Override
+ protected GnssTestDetails executeTests() {
+ JUnitCore testRunner = new JUnitCore();
+ testRunner.addListener(new GnssRunListener());
+
+ Computer computer = new Computer();
+ RunnerBuilder runnerBuilder = new GnssRunnerBuilder();
+
+ Runner runner;
+ try {
+ runner = computer.getSuite(runnerBuilder, new Class[]{ mTestClass });
+ } catch (Exception e) {
+ return new GnssTestDetails(
+ getTestClassName(),
+ GnssTestDetails.ResultCode.FAIL,
+ "[JUnit Initialization]" + e.getMessage());
+ }
+
+ Request request = Request.runner(runner);
+ Result result = testRunner.run(request);
+ return new GnssTestDetails(getApplicationContext(), getClass().getName(), result);
+ }
+
+ /**
+ * A {@link RunnerBuilder} that is used to inject during execution a {@link GnssCtsTestSuite}.
+ */
+ private class GnssRunnerBuilder extends RunnerBuilder {
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Throwable {
+ TestSuite testSuite;
+ if (hasSuiteMethod(testClass)) {
+ Test test = SuiteMethod.testFromSuiteMethod(testClass);
+ if (test instanceof TestSuite) {
+ testSuite = (TestSuite) test;
+ } else {
+ throw new IllegalArgumentException(
+ testClass.getName() + "#suite() did not return a TestSuite.");
+ }
+ } else {
+ testSuite = new TestSuite(testClass);
+ }
+ GnssCtsTestSuite gnssTestSuite =
+ new GnssCtsTestSuite(getApplicationContext(), testSuite);
+ return new JUnit38ClassRunner(gnssTestSuite);
+ }
+
+ private boolean hasSuiteMethod(Class<?> testClass) {
+ try {
+ testClass.getMethod("suite");
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Dummy {@link RunListener}.
+ * It is only used to handle logging into the UI.
+ */
+ private class GnssRunListener extends RunListener {
+ private volatile boolean mCurrentTestReported;
+
+ public void testRunStarted(Description description) throws Exception {
+ // nothing to log
+ }
+
+ public void testRunFinished(Result result) throws Exception {
+ // nothing to log
+ vibrate((int)TimeUnit.SECONDS.toMillis(2));
+ playSound();
+ }
+
+ public void testStarted(Description description) throws Exception {
+ mCurrentTestReported = false;
+ }
+
+ public void testFinished(Description description) throws Exception {
+ if (!mCurrentTestReported) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mTextView.append("\n Test passed: " + description.getMethodName());
+ }
+ });
+ }
+ }
+
+ public void testFailure(Failure failure) throws Exception {
+ mCurrentTestReported = true;
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mTextView.setText(""); // clear running status
+ mTextView.append("\n Test failed: " + failure.getDescription().getMethodName()
+ + "\n Error: " + failure.toString());
+ }
+ });
+ }
+
+ public void testAssumptionFailure(Failure failure) {
+ mCurrentTestReported = true;
+
+ }
+
+ public void testIgnored(Description description) throws Exception {
+ mCurrentTestReported = true;
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestResult.java
new file mode 100644
index 0000000..6bb7ffc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestResult.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Protectable;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+import java.util.Enumeration;
+
+/**
+ * A wrapper class for a {@link TestResult}.
+ *
+ * It provides a way to inject augmented data and helper objects during the execution of tests.
+ * i.e. inject a Context object for use by tests.
+ */
+public class GnssCtsTestResult extends TestResult {
+ private final Context mContext;
+ private final TestResult mWrappedTestResult;
+
+ private volatile boolean mInterrupted;
+
+ public GnssCtsTestResult(Context context, TestResult testResult) {
+ mContext = context;
+ mWrappedTestResult = testResult;
+ }
+
+ @Override
+ public void addError(Test test, Throwable throwable) {
+ mWrappedTestResult.addError(test, throwable);
+ }
+
+ @Override
+ public void addFailure(Test test, AssertionFailedError assertionFailedError) {
+ mWrappedTestResult.addFailure(test, assertionFailedError);
+ }
+
+ @Override
+ public void addListener(TestListener testListener) {
+ mWrappedTestResult.addListener(testListener);
+ }
+
+ @Override
+ public void removeListener(TestListener testListener) {
+ mWrappedTestResult.removeListener(testListener);
+ }
+
+ @Override
+ public void endTest(Test test) {
+ mWrappedTestResult.endTest(test);
+ }
+
+ @Override
+ public int errorCount() {
+ return mWrappedTestResult.errorCount();
+ }
+
+ @Override
+ public Enumeration<TestFailure> errors() {
+ return mWrappedTestResult.errors();
+ }
+
+ @Override
+ public int failureCount() {
+ return mWrappedTestResult.failureCount();
+ }
+
+ @Override
+ public Enumeration<TestFailure> failures() {
+ return mWrappedTestResult.failures();
+ }
+
+ @Override
+ public int runCount() {
+ return mWrappedTestResult.runCount();
+ }
+
+ @Override
+ public void runProtected(Test test, Protectable protectable) {
+ try {
+ protectable.protect();
+ } catch (AssertionFailedError e) {
+ addFailure(test, e);
+ } catch (ThreadDeath e) {
+ throw e;
+ } catch (InterruptedException e) {
+ mInterrupted = true;
+ addError(test, e);
+ } catch (Throwable e) {
+ addError(test, e);
+ }
+ }
+
+ @Override
+ public boolean shouldStop() {
+ return mInterrupted || mWrappedTestResult.shouldStop();
+ }
+
+ @Override
+ public void startTest(Test test) {
+ mWrappedTestResult.startTest(test);
+ }
+
+ @Override
+ public void stop() {
+ mWrappedTestResult.stop();
+ }
+
+ @Override
+ public boolean wasSuccessful() {
+ return mWrappedTestResult.wasSuccessful();
+ }
+
+ @Override
+ protected void run(TestCase testCase) {
+ if (testCase instanceof AndroidTestCase) {
+ AndroidTestCase gnssTestCase = (AndroidTestCase) testCase;
+ gnssTestCase.setContext(mContext);
+ //sensorTestCase.setEmulateSensorUnderLoad(false);
+ //sensorTestCase.setCurrentTestNode(new TestNode(testCase));
+ // TODO: set delayed assertion provider
+ } else {
+ throw new IllegalStateException("TestCase invalid.");
+ }
+ super.run(testCase);
+ }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestSuite.java
new file mode 100644
index 0000000..0a724b6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestSuite.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import android.content.Context;
+
+import java.util.Enumeration;
+
+/**
+ * A wrapper class for a {@link TestSuite}.
+ *
+ * It provides a way to inject a {@link GnssCtsTestResult} during execution.
+ */
+public class GnssCtsTestSuite extends TestSuite {
+ private final Context mContext;
+ private final TestSuite mWrappedTestSuite;
+
+ public GnssCtsTestSuite(Context context, TestSuite testSuite) {
+ mContext = context;
+ mWrappedTestSuite = testSuite;
+ }
+
+ @Override
+ public void run(TestResult testResult) {
+ mWrappedTestSuite.run(new GnssCtsTestResult(mContext, testResult));
+ }
+
+ @Override
+ public void addTest(Test test) {
+ mWrappedTestSuite.addTest(test);
+ }
+
+ @Override
+ public int countTestCases() {
+ return mWrappedTestSuite.countTestCases();
+ }
+
+ @Override
+ public String getName() {
+ return mWrappedTestSuite.getName();
+ }
+
+ @Override
+ public void runTest(Test test, TestResult testResult) {
+ mWrappedTestSuite.runTest(test, testResult);
+ }
+
+ @Override
+ public void setName(String name) {
+ mWrappedTestSuite.setName(name);
+ }
+
+ @Override
+ public Test testAt(int index) {
+ return mWrappedTestSuite.testAt(index);
+ }
+
+ @Override
+ public int testCount() {
+ return mWrappedTestSuite.testCount();
+ }
+
+ @Override
+ public Enumeration<Test> tests() {
+ return mWrappedTestSuite.tests();
+ }
+
+ @Override
+ public String toString() {
+ return mWrappedTestSuite.toString();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/IGnssTestStateContainer.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/IGnssTestStateContainer.java
new file mode 100644
index 0000000..498c599
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/IGnssTestStateContainer.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import android.content.ContentResolver;
+import android.content.Intent;
+
+/**
+ * An interface that defines a facade for {@link BaseGnssTestActivity}, so it can be consumed by
+ * other CtsVerifier Sensor Test Framework helper components.
+ */
+public interface IGnssTestStateContainer {
+
+ /**
+ * Waits for the operator to acknowledge to continue execution.
+ */
+ void waitForUserToContinue() throws InterruptedException;
+
+ /**
+ * @param resId The resource Id to extract.
+ * @return The extracted string.
+ */
+ String getString(int resId);
+
+ /**
+ * @param resId The resource Id to extract.
+ * @param params The parameters to format the string represented by the resource contents.
+ * @return The formatted extracted string.
+ */
+ String getString(int resId, Object... params);
+
+ /**
+ * Starts an Activity and blocks until it completes, then it returns its result back to the
+ * client.
+ *
+ * @param action The action to start the Activity.
+ * @return The Activity's result code.
+ */
+ int executeActivity(String action) throws InterruptedException;
+
+ /**
+ * Starts an Activity and blocks until it completes, then it returns its result back to the
+ * client.
+ *
+ * @param intent The intent to start the Activity.
+ * @return The Activity's result code.
+ */
+ int executeActivity(Intent intent) throws InterruptedException;
+
+ /**
+ * @return The {@link ContentResolver} associated with the test.
+ */
+ ContentResolver getContentResolver();
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/reporting/GnssTestDetails.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/reporting/GnssTestDetails.java
new file mode 100644
index 0000000..ea04123
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/reporting/GnssTestDetails.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.reporting;
+
+import com.android.cts.verifier.R;
+
+import org.junit.runner.Result;
+
+import android.content.Context;
+
+/**
+ * A class that holds the result of a Gnss test execution.
+ */
+public class GnssTestDetails {
+ private final String mName;
+ private final ResultCode mResultCode;
+ private final String mSummary;
+
+ public enum ResultCode {
+ SKIPPED,
+ PASS,
+ FAIL,
+ INTERRUPTED
+ }
+
+ public GnssTestDetails(String name, ResultCode resultCode) {
+ this(name, resultCode, null /* summary */);
+ }
+
+ public GnssTestDetails(String name, ResultCode resultCode, String summary) {
+ mName = name;
+ mResultCode = resultCode;
+ mSummary = summary;
+ }
+
+ public GnssTestDetails(
+ Context context,
+ String name,
+ int passCount,
+ int skipCount,
+ int failCount) {
+ ResultCode resultCode = ResultCode.PASS;
+ if (failCount > 0) {
+ resultCode = ResultCode.FAIL;
+ } else if (skipCount > 0) {
+ resultCode = ResultCode.SKIPPED;
+ }
+
+ mName = name;
+ mResultCode = resultCode;
+ mSummary = context.getString(R.string.snsr_test_summary, passCount, skipCount, failCount);
+ }
+
+ public GnssTestDetails(Context context, String name, Result result) {
+ this(context,
+ name,
+ result.getRunCount() - result.getFailureCount() - result.getIgnoreCount(),
+ result.getIgnoreCount(),
+ result.getFailureCount());
+ }
+
+ public GnssTestDetails(String name, String tag, Throwable cause) {
+ ResultCode resultCode = ResultCode.FAIL;
+ if (cause instanceof InterruptedException) {
+ resultCode = ResultCode.INTERRUPTED;
+ // the interrupted status must be restored, so other routines can consume it
+ Thread.currentThread().interrupt();
+ }
+ mName = name;
+ mResultCode = resultCode;
+ mSummary = String.format("[%s] %s", tag, cause.getMessage());
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public ResultCode getResultCode() {
+ return mResultCode;
+ }
+
+ public String getSummary() {
+ return mSummary;
+ }
+
+ public GnssTestDetails cloneAndChangeResultCode(ResultCode resultCode) {
+ return new GnssTestDetails(mName, resultCode, mSummary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s|%s|%s", mName, mResultCode.name(), mSummary);
+ }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 4f26b9c..4e39720 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.UserManager;
import android.util.Log;
@@ -55,6 +56,7 @@
public static final String COMMAND_PROFILE_OWNER_CLEAR_POLICIES = "po-clear-policies";
public static final String COMMAND_REMOVE_DEVICE_OWNER = "remove-device-owner";
public static final String COMMAND_REQUEST_BUGREPORT = "request-bugreport";
+ public static final String COMMAND_SET_USER_ICON = "set-user-icon";
public static final String EXTRA_USER_RESTRICTION =
"com.android.cts.verifier.managedprovisioning.extra.USER_RESTRICTION";
@@ -161,6 +163,13 @@
}
clearProfileOwnerRelatedPolicies();
} break;
+ case COMMAND_SET_USER_ICON: {
+ if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+ return;
+ }
+ mDpm.setUserIcon(mAdmin, BitmapFactory.decodeResource(getResources(),
+ com.android.cts.verifier.R.drawable.icon));
+ } break;
}
} catch (Exception e) {
Log.e(TAG, "Failed to execute command: " + intent, e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 8e0dcb6..163f2fe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -66,6 +66,7 @@
private static final String DISALLOW_CONFIG_WIFI_ID = "DISALLOW_CONFIG_WIFI";
private static final String DISALLOW_CONFIG_VPN_ID = "DISALLOW_CONFIG_VPN";
private static final String DISALLOW_USB_FILE_TRANSFER_ID = "DISALLOW_USB_FILE_TRANSFER";
+ private static final String SET_USER_ICON_TEST_ID = "SET_USER_ICON";
private static final String DISALLOW_DATA_ROAMING_ID = "DISALLOW_DATA_ROAMING";
private static final String POLICY_TRANSPARENCY_TEST_ID = "POLICY_TRANSPARENCY";
private static final String REMOVE_DEVICE_OWNER_TEST_ID = "REMOVE_DEVICE_OWNER";
@@ -256,6 +257,17 @@
CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
false))}));
+ adapter.add(createInteractiveTestItem(this, SET_USER_ICON_TEST_ID,
+ R.string.device_owner_set_user_icon,
+ R.string.device_owner_set_user_icon_instruction,
+ new ButtonInfo[] {
+ new ButtonInfo(
+ R.string.device_owner_set_user_icon_button,
+ createSetUserIconIntent()),
+ new ButtonInfo(
+ R.string.device_owner_settings_go,
+ new Intent(Settings.ACTION_SETTINGS))}));
+
// setPermissionGrantState
adapter.add(createTestItem(this, CHECK_PERMISSION_LOCKDOWN_TEST_ID,
R.string.device_profile_owner_permission_lockdown_test,
@@ -307,4 +319,10 @@
.putExtra(CommandReceiverActivity.EXTRA_USER_RESTRICTION, restriction)
.putExtra(CommandReceiverActivity.EXTRA_ENFORCED, true);
}
+
+ private Intent createSetUserIconIntent() {
+ return new Intent(this, CommandReceiverActivity.class)
+ .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
+ CommandReceiverActivity.COMMAND_SET_USER_ICON);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index e8e2cee..56c8ac0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.media.tv.TvContract;
+import android.media.tv.TvInputManager;
import android.os.AsyncTask;
import android.view.View;
@@ -36,6 +37,8 @@
TvContract.Channels.CONTENT_URI);
private static final Intent EPG_INTENT = new Intent(Intent.ACTION_VIEW,
TvContract.Programs.CONTENT_URI);
+ private static final Intent TV_TRIGGER_SETUP_INTENT = new Intent(
+ TvInputManager.ACTION_SETUP_INPUTS);
private static final long TIMEOUT_MS = 5l * 60l * 1000l; // 5 mins.
@@ -47,6 +50,8 @@
private View mVerifyGlobalSearchItem;
private View mGoToEpgItem;
private View mVerifyEpgItem;
+ private View mTriggerSetupItem;
+ private View mVerifyTriggerSetupItem;
private boolean mTuneVerified;
private boolean mOverlayViewVerified;
private boolean mGlobalSearchVerified;
@@ -109,6 +114,13 @@
setButtonEnabled(mVerifyEpgItem, true);
} else if (containsButton(mVerifyEpgItem, v)) {
setPassState(mVerifyEpgItem, true);
+ setButtonEnabled(mTriggerSetupItem, true);
+ } else if (containsButton(mTriggerSetupItem, v)) {
+ startActivity(TV_TRIGGER_SETUP_INTENT);
+ setPassState(mTriggerSetupItem, true);
+ setButtonEnabled(mVerifyTriggerSetupItem, true);
+ } else if (containsButton(mVerifyTriggerSetupItem, v)) {
+ setPassState(mVerifyTriggerSetupItem, true);
getPassButton().setEnabled(true);
}
}
@@ -130,6 +142,10 @@
R.string.tv_launch_epg, this);
mVerifyEpgItem = createUserItem(R.string.tv_input_discover_test_verify_epg,
android.R.string.yes, this);
+ mTriggerSetupItem = createUserItem(R.string.tv_input_discover_test_trigger_setup,
+ R.string.tv_launch_setup, this);
+ mVerifyTriggerSetupItem = createUserItem(
+ R.string.tv_input_discover_test_verify_trigger_setup, android.R.string.yes, this);
}
@Override
diff --git a/build/device_info_package.mk b/build/device_info_package.mk
index 0ccb05d..b91c264 100644
--- a/build/device_info_package.mk
+++ b/build/device_info_package.mk
@@ -20,7 +20,6 @@
DEVICE_INFO_INSTRUMENT := android.support.test.runner.AndroidJUnitRunner
DEVICE_INFO_PERMISSIONS += android.permission.WRITE_EXTERNAL_STORAGE
DEVICE_INFO_ACTIVITIES += \
- $(DEVICE_INFO_PACKAGE).CameraDeviceInfo \
$(DEVICE_INFO_PACKAGE).ConfigurationDeviceInfo \
$(DEVICE_INFO_PACKAGE).CpuDeviceInfo \
$(DEVICE_INFO_PACKAGE).FeatureDeviceInfo \
diff --git a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java
index d2380af..385f22f 100644
--- a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java
+++ b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java
@@ -18,6 +18,7 @@
import android.app.KeyguardManager;
import android.content.Context;
+import android.os.Build;
/**
* ScreenLockHelper is used to check whether the device is protected by a locked screen.
@@ -29,6 +30,9 @@
* is no way to programmatically distinguish between the two.
*/
public static boolean isDeviceSecure(Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return true; // KeyguardManager.isDeviceSecure() added in M, skip this check
+ }
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
return km.isDeviceSecure();
}
diff --git a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java
index 70a4b03..ef63544 100644
--- a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java
+++ b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.os.Build;
/**
* WifiHelper is used to check whether the device is connected to WiFi.
@@ -27,6 +28,9 @@
public class WifiHelper {
public static boolean isWifiConnected(Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ return true; // ConnectivityManager.getNetworkInfo() added in LOLLIPOP, skip this check
+ }
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiNetworkInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
index 57b9e3e..cb81d0b 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
@@ -37,7 +37,8 @@
public class DeviceReportLog extends ReportLog {
private static final String TAG = DeviceReportLog.class.getSimpleName();
private static final String RESULT = "COMPATIBILITY_TEST_RESULT";
- private static final String DEFAULT_REPORT_LOG_NAME = "DefaultTestMetrics";
+ // TODO(mishragaurav): Remove default names and constructor after fixing b/27950009.
+ private static final String DEFAULT_REPORT_LOG_NAME = "DefaultDeviceTestMetrics";
private static final String DEFAULT_STREAM_NAME = "DefaultStream";
private static final int INST_STATUS_ERROR = -1;
private static final int INST_STATUS_IN_PROGRESS = 2;
@@ -72,7 +73,7 @@
@Override
public void addValue(String source, String message, double value, ResultType type,
- ResultUnit unit) {
+ ResultUnit unit) {
super.addValue(source, message, value, type, unit);
try {
store.addResult(message, value);
@@ -82,8 +83,7 @@
}
@Override
- public void addValue(String message, double value, ResultType type,
- ResultUnit unit) {
+ public void addValue(String message, double value, ResultType type, ResultUnit unit) {
super.addValue(message, value, type, unit);
try {
store.addResult(message, value);
@@ -94,7 +94,7 @@
@Override
public void addValues(String source, String message, double[] values, ResultType type,
- ResultUnit unit) {
+ ResultUnit unit) {
super.addValues(source, message, values, type, unit);
try {
store.addArrayResult(message, values);
@@ -104,8 +104,7 @@
}
@Override
- public void addValues(String message, double[] values, ResultType type,
- ResultUnit unit) {
+ public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
super.addValues(message, values, type, unit);
try {
store.addArrayResult(message, values);
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
index 67e6c39..fd61b08 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
@@ -57,8 +57,8 @@
}
mJsonFile.createNewFile();
formatWriter = new BufferedWriter(new FileWriter(mJsonFile));
- formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0,
- oldMetrics.length() + mStreamName.length() + 3);
+ formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0, oldMetrics.length() +
+ mStreamName.length() + 3);
formatWriter.flush();
formatWriter.close();
mJsonWriter = new JsonWriter(new FileWriter(mJsonFile, true));
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
index b8887cf..25fb4d7 100644
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
+++ b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
@@ -88,10 +88,10 @@
}
public void testFile() throws Exception {
- final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
assertTrue("External storage is not mounted",
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED));
- assertTrue("Report Log directory missing", dir.isDirectory());
+ final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
+ assertTrue("Report Log directory missing", dir.isDirectory() || dir.mkdirs());
// Remove files from earlier possible runs.
File[] files = dir.listFiles();
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 14f3812..81d78c0 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -196,7 +196,7 @@
@Override
public void testStarted(TestIdentifier test) {
mCurrentCaseResult = mCurrentModuleResult.getOrCreateResult(test.getClassName());
- mCurrentResult = mCurrentCaseResult.getOrCreateResult(test.getTestName());
+ mCurrentResult = mCurrentCaseResult.getOrCreateResult(test.getTestName().trim());
mCurrentResult.reset();
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
index c786ef4..1ee7dd3 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
@@ -25,6 +25,7 @@
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetCleaner;
import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.util.FileUtil;
import java.io.BufferedWriter;
import java.io.File;
@@ -43,6 +44,9 @@
@Option(name = "dest-dir", description = "The directory under the result to store the files")
private String mDestDir;
+ @Option(name = "temp-dir", description = "The temp directory containing host-side report logs")
+ private String mTempReportFolder;
+
public ReportLogCollector() {
}
@@ -79,19 +83,47 @@
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
try {
File resultDir = buildHelper.getResultDir();
+ if (mDestDir != null) {
+ resultDir = new File(resultDir, mDestDir);
+ }
+ resultDir.mkdirs();
+ if (!resultDir.isDirectory()) {
+ CLog.e("%s is not a directory", resultDir.getAbsolutePath());
+ return;
+ }
String resultPath = resultDir.getAbsolutePath();
- pull(device, mSrcDir, resultPath);
- } catch (FileNotFoundException fnfe) {
- fnfe.printStackTrace();
+ final File hostReportDir = FileUtil.createNamedTempDir(mTempReportFolder);
+ if (!hostReportDir.isDirectory()) {
+ CLog.e("%s is not a directory", hostReportDir.getAbsolutePath());
+ return;
+ }
+ String hostReportsPath = hostReportDir.getAbsolutePath();
+ pull(device, mSrcDir, hostReportsPath, resultPath);
+ } catch (Exception exception) {
+ exception.printStackTrace();
}
}
- private void pull(ITestDevice device, String src, String dest) {
- String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(), src, dest);
+ private void pull(ITestDevice device, String deviceSrc, String hostSrc, String dest) {
+ String deviceSideCommand = String.format("adb -s %s pull %s %s", device.getSerialNumber(),
+ deviceSrc, dest);
+ String hostSideCommand = String.format("cp -r %s/* %s", hostSrc, dest);
+ String cleanUpCommand = String.format("rm -rf %s", hostSrc);
try {
- Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
- if (p.waitFor() != 0) {
- CLog.e("Failed to run %s", command);
+ Process deviceProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+ deviceSideCommand});
+ if (deviceProcess.waitFor() != 0) {
+ CLog.v("No device-side report logs pulled.");
+ }
+ Process hostProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+ hostSideCommand});
+ if (hostProcess.waitFor() != 0) {
+ CLog.v("No host-side report logs pulled");
+ }
+ Process cleanUpProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+ cleanUpCommand});
+ if (cleanUpProcess.waitFor() != 0) {
+ CLog.e("Failed to run %s", cleanUpCommand);
}
} catch (Exception e) {
CLog.e("Caught exception during pull.");
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java b/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java
index 4a3613d..a17f17a 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java
@@ -27,8 +27,12 @@
public class HostInfoStore extends InfoStore {
- private final File mJsonFile;
- private JsonWriter mJsonWriter = null;
+ protected File mJsonFile;
+ protected JsonWriter mJsonWriter = null;
+
+ public HostInfoStore() {
+ mJsonFile = null;
+ }
public HostInfoStore(File file) throws Exception {
mJsonFile = file;
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
index 4675231..e590b91 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
@@ -16,6 +16,11 @@
package com.android.compatibility.common.util;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.IOException;
+
/**
* A {@link ReportLog} that can be used with the in memory metrics store used for host side metrics.
*/
@@ -24,6 +29,14 @@
private final String mAbi;
private final String mClassMethodName;
+ // TODO(mishragaurav): Remove default names and constructor after fixing b/27950009.
+ private static final String DEFAULT_REPORT_LOG_NAME = "DefaultHostTestMetrics";
+ private static final String DEFAULT_STREAM_NAME = "DefaultStream";
+ // Temporary folder must match the temp-dir value configured in ReportLogCollector target
+ // preparer in cts/tools/cts-tradefed/res/config/cts-oreconditions.xml
+ private static final String TEMPORARY_REPORT_FOLDER = "temp-report-logs/";
+ private ReportLogHostInfoStore store;
+
/**
* @param deviceSerial serial number of the device
* @param abi abi the test was run on
@@ -31,12 +44,58 @@
* Note that ReportLog.getClassMethodNames() provide this.
*/
public MetricsReportLog(String deviceSerial, String abi, String classMethodName) {
+ this(deviceSerial, abi, classMethodName, DEFAULT_REPORT_LOG_NAME, DEFAULT_STREAM_NAME);
+ }
+
+ public MetricsReportLog(String deviceSerial, String abi, String classMethodName,
+ String reportLogName) {
+ this(deviceSerial, abi, classMethodName, reportLogName, DEFAULT_STREAM_NAME);
+ }
+
+ public MetricsReportLog(String deviceSerial, String abi, String classMethodName,
+ String reportLogName, String streamName) {
+ super(reportLogName, streamName);
mDeviceSerial = deviceSerial;
mAbi = abi;
mClassMethodName = classMethodName;
+ try {
+ final File dir = FileUtil.createNamedTempDir(TEMPORARY_REPORT_FOLDER);
+ File jsonFile = new File(dir, mReportLogName + ".reportlog.json");
+ store = new ReportLogHostInfoStore(jsonFile, mStreamName);
+ store.open();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void addValue(String source, String message, double value, ResultType type,
+ ResultUnit unit) {
+ super.addValue(source, message, value, type, unit);
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void addValue(String message, double value, ResultType type, ResultUnit unit) {
+ super.addValue(message, value, type, unit);
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
}
public void submit() {
+ try {
+ store.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
MetricsStore.storeResult(mDeviceSerial, mAbi, mClassMethodName, this);
}
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
new file mode 100644
index 0000000..65114d9
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import com.android.json.stream.JsonWriter;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class ReportLogHostInfoStore extends HostInfoStore {
+
+ private final String mStreamName;
+
+ public ReportLogHostInfoStore(File jsonFile, String streamName) throws Exception {
+ mJsonFile = jsonFile;
+ mStreamName = streamName;
+ }
+
+ /**
+ * Creates the writer and starts the JSON Object for the metric stream.
+ */
+ @Override
+ public void open() throws IOException {
+ BufferedWriter formatWriter;
+ String oldMetrics;
+ if (mJsonFile.exists()) {
+ BufferedReader jsonReader = new BufferedReader(new FileReader(mJsonFile));
+ StringBuilder oldMetricsBuilder = new StringBuilder();
+ String line;
+ while ((line = jsonReader.readLine()) != null) {
+ oldMetricsBuilder.append(line);
+ }
+ oldMetrics = oldMetricsBuilder.toString().trim();
+ if (oldMetrics.charAt(oldMetrics.length() - 1) == '}') {
+ oldMetrics = oldMetrics.substring(0, oldMetrics.length() - 1);
+ }
+ oldMetrics = oldMetrics + ",";
+ } else {
+ oldMetrics = "{";
+ }
+ mJsonFile.createNewFile();
+ formatWriter = new BufferedWriter(new FileWriter(mJsonFile));
+ formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0, oldMetrics.length() +
+ mStreamName.length() + 3);
+ formatWriter.flush();
+ formatWriter.close();
+ mJsonWriter = new JsonWriter(new FileWriter(mJsonFile, true));
+ mJsonWriter.beginObject();
+ }
+
+ /**
+ * Closes the writer.
+ */
+ @Override
+ public void close() throws IOException {
+ mJsonWriter.endObject();
+ mJsonWriter.close();
+ // Close the overall JSON object
+ BufferedWriter formatWriter = new BufferedWriter(new FileWriter(mJsonFile, true));
+ formatWriter.write("}", 0, 1);
+ formatWriter.flush();
+ formatWriter.close();
+ }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/TestFilter.java b/common/util/src/com/android/compatibility/common/util/TestFilter.java
index 78b68cfc..47ed9ec 100644
--- a/common/util/src/com/android/compatibility/common/util/TestFilter.java
+++ b/common/util/src/com/android/compatibility/common/util/TestFilter.java
@@ -27,15 +27,20 @@
/**
* Builds a new {@link TestFilter} from the given string. Filters can be in one of four forms,
* the instance will be initialized as;
- * -"name" -> abi = null, name = "name", test = null
- * -"name" "test" -> abi = null, name = "name", test = "test"
- * -"abi" "name" -> abi = "abi", name = "name", test = null
- * -"abi" "name" test" -> abi = "abi", name = "name", test = "test"
+ * -"name" -> abi = null, name = "name", test = null
+ * -"name" "test..." -> abi = null, name = "name", test = "test..."
+ * -"abi" "name" -> abi = "abi", name = "name", test = null
+ * -"abi" "name" "test..." -> abi = "abi", name = "name", test = "test..."
+ *
+ * Test identifier can contain multiple parts, eg parameterized tests.
*
* @param filter the filter to parse
* @return the {@link TestFilter}
*/
public static TestFilter createFrom(String filter) {
+ if (filter.isEmpty()) {
+ throw new IllegalArgumentException("Filter was empty");
+ }
String[] parts = filter.split(" ");
String abi = null, name = null, test = null;
// Either:
@@ -45,20 +50,18 @@
// <abi> <name> <test>
if (parts.length == 1) {
name = parts[0];
- } else if (parts.length == 2) {
+ } else {
+ int index = 0;
if (AbiUtils.isAbiSupportedByCompatibility(parts[0])) {
abi = parts[0];
- name = parts[1];
- } else {
- name = parts[0];
- test = parts[1];
+ index++;
}
- } else if (parts.length == 3){
- abi = parts[0];
- name = parts[1];
- test = parts[2];
- } else {
- throw new IllegalArgumentException(String.format("Could not parse filter: %s", filter));
+ name = parts[index];
+ index++;
+ parts = filter.split(" ", index + 1);
+ if (parts.length > index) {
+ test = parts[index];
+ }
}
return new TestFilter(abi, name, test);
}
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 0218897..258192d 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -25,6 +25,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_RESOURCE_DIRS := res
+
LOCAL_CTS_TEST_PACKAGE := android.appsecurity
# tag this module as a cts test artifact
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.pk8
new file mode 100644
index 0000000..d500d70
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.x509.pem
new file mode 100644
index 0000000..e230eb0
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.x509.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsTCCAnGgAwIBAgIJAP6EmkoBF8UoMAkGByqGSM44BAMwEzERMA8GA1UEAwwI
+ZHNhLTEwMjQwHhcNMTYwMzMxMTUyNzEwWhcNNDMwODE3MTUyNzEwWjATMREwDwYD
+VQQDDAhkc2EtMTAyNDCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCTDpv8gS5Y+Ehl
+oln6WT/MYBnywrc3tWDfnlY+9MpVDdB2+kcB7WrhobW1L+6ayKmlkrTaAFjiMPDf
+bdyA6hy3fDu1teLCb89R0uodfZa3MDXXlmqvBk4Fdw8fYijWI/q175e4Y5sNYO9+
+QZg8bBIZnxxCdbKASJ6NAHc50ts3vwIVAIebRw3HnYOZbo6rPoBmcBOxcZTLAoGA
+ch+0D7JrbqmR1w5S3VBtTnONLiBYnaz1Ri3Pfiw5FHKfJcfFcQopIOLJwfdBmY4b
+FLGV5u7DXeJNp16Nvl4MrsmVjkWs9MZVAp5RqzrN9JhVi4ShpdelyFjdWOXHPbc7
+NNqQpTjdkK23r/tCE6XkvkCiWm7Rt22LMpZA4ePALIoDgYQAAoGAc8SkppDzSUPH
+SpKrhrldRyh5m4wSH14ZE96mlSze9tRoSDo8hsA9/vGLgoN7F+3jYSvj8m42tmNt
+jZJWk7vPkJHC/9qoEGbVBY+aTNYwVJyKDJ07vZB9bLxpjD/yyQlsn7/vZTOS657c
+W2S817RgGGyGcCNRoKNig6i0k9fzE8ajUDBOMB0GA1UdDgQWBBSPwzoIjftVH2ke
+EJXtLq+bB50lzDAfBgNVHSMEGDAWgBSPwzoIjftVH2keEJXtLq+bB50lzDAMBgNV
+HRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUH1GQcpqx8/9p9QfhCRMvcxrECM4C
+FH8ZULK91BMaHodbRMUtdxB9kIbL
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.pk8
new file mode 100644
index 0000000..cf63594
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.x509.pem
new file mode 100644
index 0000000..705db39
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.x509.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEWzCCBAKgAwIBAgIJAK4uYtTAat4+MAkGByqGSM44BAMwEzERMA8GA1UEAwwI
+ZHNhLTIwNDgwHhcNMTYwMzMxMTgzMDAxWhcNNDMwODE3MTgzMDAxWjATMREwDwYD
+VQQDDAhkc2EtMjA0ODCCA0cwggI5BgcqhkjOOAQBMIICLAKCAQEAv2/yUkci8fnZ
+ppepy1kcOTIrbPJTW46Z2jKOWjHCTd1aqRFunz3gllpx/YDgjboNIYZf2jKhk2gi
+MgF+8OT0hEHQGXSofnqRoVljexA2nC3tPhVyjN14pQ7ZJXp/raHh1uCT5K7Lfafc
+8y5Cs180CdfisspANfCp10jFu1D2hKOLfggUA9efN05c0f2yOx/Pm9uEiz6ftLUJ
+UWgcJenx1WUk4Nb1qMOWgg9nKQyDiBxZKoVCH5/XJO0K225w6F4scol2hMdTRlA+
+9TGb5tvHKT+Y+lE7fBbcBSKzLT3pwD/T08ErpsIoHqRPamLGHeuamGzvXLHwI1UN
+cJNGg2nnCwIhAJz9K+Qpgg7sbqRMeRvIf2cuWRWbi4XnYR+IAGqgfYUZAoIBADks
+N3taHUnIvkcxTuEUiCSb+d1KMlvbZiH5zLVIyzi5kZNQW8L/gR23z8T6qngXXnFw
+tcTRcb0TDqR7iYPxsX3/x+jBjiApIgebqpnPdpiEAUfORZX7w6CpCNsp9Kqxb98z
+4PtKE9z/20Q3zKhqlwDm8uSjjT7E5xw/YpV8bg7YuQ5eQ8mkonipNXllf3qmDV48
+see/+QwIeBiL7jTjgeBv5ziL8BY2AYmfOwGKwmK9ERxJpIoxgS+5fFuA2oAQ8CwJ
+UDwwv5Wbz7NVkvljHK1Fh5u26ZHdeLT4qp4F0GamJcikq4MqFco6ToCvp8NoDNMZ
+MOno2k1IvsIwrIbrQJgDggEGAAKCAQEAuxbFbx2H4n4BqfbkC9tjn/Mg3zr4LZgG
+7v3FWpzpkbAcEcFCVIqTmJiRlsuf4ml/t9hflOvarfD6TesSc7gyGCJ/2QiqJcI+
+Vif5AKqZskQFlZ5BUMIMjPFMy1WtTVpEotmdbIOaQif4wQrz6SNFUOAXPBKRTY33
+HOLMoo8FRiZ1+uMu9PlUWYqMhSJg+rm2AQPt06D+JToXREaNkYjN0K97T2MTcUNh
+OWiliH/zFuF8N2s6IlNaCv1Yc4FoYEIRoS07dUxcjrV9KRd0TyU0q++rRPluytJP
+yAoyTIrfwa2SM5JR9RtdBZsPdR9Ckpy4ZKSJqDzTbCIU70zsGgHA4aNQME4wHQYD
+VR0OBBYEFL3koBjVHAySf8Xr196yqDT6VhwSMB8GA1UdIwQYMBaAFL3koBjVHAyS
+f8Xr196yqDT6VhwSMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwNIADBFAiEAjowh
+laeXA/CUrHt6iH4u6edWGeZzyFGlpWsxssKTMBECIG2tZs/xnZVAtXioiIcH1CXT
+LN5AAzZ8wlNUKSvTc12j
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.pk8
new file mode 100644
index 0000000..f0f8983
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.x509.pem
new file mode 100644
index 0000000..0284b13
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3DCCBYKgAwIBAgIJAKmpH5wXPDbGMAkGByqGSM44BAMwEzERMA8GA1UEAwwI
+ZHNhLTMwNzIwHhcNMTYwMzMxMTgzMjU2WhcNNDMwODE3MTgzMjU2WjATMREwDwYD
+VQQDDAhkc2EtMzA3MjCCBMcwggM5BgcqhkjOOAQBMIIDLAKCAYEAscwotTL9jjwZ
+CpGRqXVezU9P0zY/wHFYMQB09JjgoCJRm0D9FZzmTnySJa4suwlwoduzgv+pkIkk
+nn0w+hL6LsblRTEuFj11o/fLLAZE4KmdIAPkCcH74HOnws4BwazJLWFtVEv+bdyj
+CmrI2urYWT5uRJwWZmkG4iUnoL/5FUv2pvpSOzu6EO+qFcFcWf3/VrQDaaP3jRRh
+iVCThxvX5xOrO24krrOFlHQufY0A6fHYQqII6EYac6tKTI+ltz121DYH914SHMe8
+0JJYpDVOatjTJADyg1AzHAKsyfTKHHpHbqkgU/CRtALEC1DUyLqQhHvBGpodmqPH
+r9Mbd7pXudw2h6O8uapAsmaFt/YdrSbd37UvhLJyyW0fodTjBTA0WiNs0CLTJL9o
+422Nt1cUDQS1JpsghAzmMWaavq7+QIRhpnMHL47p1jCZvcwMboMlcJwOCjyyZS0F
+fmaD+pEi56Lx+9XDblESM78crb8/lbvuohyrwIJciQmL0hQoKIg1AiEApYT1sROj
+BMB4FIQaS86VKdJ4h9OR13AraES3ba9WV1cCggGAI9LskZ7wcUna6nZyGT4f3bH1
+KSeD3602Yd86NKuB8QGr/QT5L+wFwCuvvI4V8P2lM4wb+q1LrR688f53WS4c0Kin
+/MeN4YtkQBzV4l04Bxrce//EcfQzUPDAr41Fwu2tA0BHE67trxGjNS7SzoFZUiDo
+d/aOZCVilFIay5oF2X8yeNcpTynsxTbGxjxhhgG2tS0fvxhbGF6rl4D0Ddskx6L/
+xjstzu0ADE8FNpDehuKqxzOisNLIJgc1INPQ06AmaUF1Pge74T2AJYPYwqfzArG3
+pj+l2iND0PM7lDeQCgivPAqhYrveoIqJe0NAEu/PiCnOW50hQ4F6dl9lzn9sGXTP
+5KxdR5OyG+Ki+nWTN8h3yOy9ZK7Gh8gUeqE3QVow4+1LhcO19C+X+NM588KbKsq9
+KRP5H4v238g6oF2wgbmPrYvqiwoa1qjHvUX7ZjQuIfrN9+lICflsHKtAtchuUIiO
+b1AWPeaJwAynTn2EeDsVd0e8bm+h+g7ZSDAwUOKuA4IBhgACggGBAJfW6T1BxtZo
+EacqR2TwTi9B3O93Zcj0OzDOn9UMahepcfaF1B3wq9UdJ4PPIC1U27CaEXEJNxgJ
+cIURfFPDXA6pLVEqrGgRX2u0FR1pmHVIxjBpvPJvO954+Hawp+ClU6PKLmxuVZpA
+VeJBx7C8/DU/58J//iuG9B6/mwzPuEoPmnGYMsfVCcEX8yQ2PZXyNGp+KnUygyql
+mMxpE8UXtH6mHYontjiw4Afxqwop3v/bG8eT5FHhpXoQDSN/oeGghDaq9DyIjCqr
+GXZDBvEufLYRgOvnpV6T0oMa9U2W2Trz3HYD6eX09FOhGnMWl9euYrSVRihAKBh1
+72ystvPy2R4wdAA5EQf7EsDdgt/QOMf/AvkaKHMP7DNK5BZxwPQ0KwRkLB+0vaDI
+Mnpu29L6TiixMxI1ihnZbR/U0v8H+/SlSjZaPNRQeuoV9d8t81miUqVSMLcpqNui
+ZljSCtoGfktPAbPyFwGenBkGK5oo0I381KTECMynC0R2P9CQUHegeaNQME4wHQYD
+VR0OBBYEFPRqMyQLPdq0guTx3YKiVxtWN+bPMB8GA1UdIwQYMBaAFPRqMyQLPdq0
+guTx3YKiVxtWN+bPMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwNJADBGAiEAjcit
+8dFR02elWKoeRAounP9TE2aqDqd5cJXqXn0ssMYCIQCIINjXEYRovfVjDotKelRg
+5k0lmzMmx6Xfz8EgZDLovw==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.pk8
new file mode 100644
index 0000000..f781c30
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.x509.pem
new file mode 100644
index 0000000..06adcfe
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbDCCARGgAwIBAgIJAMoPtk37ZudyMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTYwMzMxMTQ1ODA2WhcNNDMwODE3MTQ1ODA2WjASMRAwDgYD
+VQQDDAdlYy1wMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpl8RPSLLSROQ
+gwesMe4roOkTi3hfrGU20U6izpDStL/hlLUM3I4Wn1SnOpke8Pp2MpglvgeMx4J0
+BwPaRLTX66NQME4wHQYDVR0OBBYEFNQTNWi5WzAVizIgceqMQ/9bBczIMB8GA1Ud
+IwQYMBaAFNQTNWi5WzAVizIgceqMQ/9bBczIMAwGA1UdEwQFMAMBAf8wCgYIKoZI
+zj0EAwIDSQAwRgIhAPUEoIZsrvAp9BcULFy3E1THn/zR1kBhjfyk8Z4W23jWAiEA
++O6kgpeZwGytCMbT0tLsBeBXQVTnR+oP27gELLZVqt0=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.pk8
new file mode 100644
index 0000000..f22507d
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.x509.pem
new file mode 100644
index 0000000..9d1403b
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.x509.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBqTCCAS6gAwIBAgIJAMRWS+CLIsxqMAoGCCqGSM49BAMDMBIxEDAOBgNVBAMM
+B2VjLXAzODQwHhcNMTYwMzMxMTUzMDU3WhcNNDMwODE3MTUzMDU3WjASMRAwDgYD
+VQQDDAdlYy1wMzg0MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE18hjdbk/HXGQNIuF
+xKPMAZO3PQnROO6izB/mHM1BKPpih2/51iMTFKn6KCU9NZt/Q4Z+PpZVLuawEWP/
+uoWwWIj+60vk25z47/Sr0icelSDGt9T9ujiNP6aTA5hc9gypo1AwTjAdBgNVHQ4E
+FgQU981MoejFjh0rbaGXODywOYvB32kwHwYDVR0jBBgwFoAU981MoejFjh0rbaGX
+ODywOYvB32kwDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEA/58rXa+F
+mB6JwB89/IAucpNlktjSPrH2tD63BSROvpUpXNy+p+OlJu4sCvY7HnwEAjEA0VWw
+QqUBFLQHFJx1JjMYYfT78V8ylY+Ns1lxrdvs29NNg45MA9uw/ZVMMHgTFNph
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.pk8
new file mode 100644
index 0000000..9c75e4c
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.x509.pem
new file mode 100644
index 0000000..a9b8194
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.x509.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB8zCCAVSgAwIBAgIJAOxXdFsvm3YiMAoGCCqGSM49BAMEMBIxEDAOBgNVBAMM
+B2VjLXA1MjEwHhcNMTYwMzMxMTUzMTIyWhcNNDMwODE3MTUzMTIyWjASMRAwDgYD
+VQQDDAdlYy1wNTIxMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAYX95sSjPEQqg
+yLD04tNUyq9y/w8seblOpfqa/Amx6H4GFdrjGXX0YTfXKr9GhAyIyQSnNrIg0zDl
+WQUbBPRW4CYBLFOg1pUn1NBhKFD4NtO1KWvYtNOYDegFjRCPB0p+fEXDbq8QFDYv
+lh+NZUJ16+ih8XNIf1C29xuLEqN6oKOnAvajUDBOMB0GA1UdDgQWBBT/Ra3kz60g
+Q7tYk3byZckcLabt8TAfBgNVHSMEGDAWgBT/Ra3kz60gQ7tYk3byZckcLabt8TAM
+BgNVHRMEBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAP39hYLsWk2H84oEw+HJ
+qGGjexhqeD3vSO1mWhopripE/81oy3yV10puYoJe11xDSfcDj2VfNCHazuXO3kSx
+GA/1AkIBLUJxp/WYbYzhBGKr6lcxczKI/wuMfkZ6vL+0EMJVA/2uEoeqvnl7Bsdk
+icyaOBNEADijuVdaPPIWzKClt9OaVxE=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.pk8
new file mode 100644
index 0000000..7b4beee
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.x509.pem
new file mode 100644
index 0000000..9498ec5
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.x509.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB9DCCAV2gAwIBAgIJAP0KtYjhFu3IMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS0xMDI0MB4XDTE2MDMzMTE2MTQ0M1oXDTQzMDgxNzE2MTQ0M1owEzER
+MA8GA1UEAwwIcnNhLTEwMjQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOOP
+r4Y+uCAihcVjey8JmdjyfhZXplVf3HnOQfvWcY97nKnJ7L977QiWajIn7iZRAdVX
+PamVrEbaU6uklgcJFG/qirtscOf6fMBf6GaP2PAhQG89MQnUt9rAjxUAakzWOBTz
+bH0gHRDEGQ30LCA1oSlbLldHz+zBKSC7nsSKYp+9AgMBAAGjUDBOMB0GA1UdDgQW
+BBT1x0TcWRB4i9JnU5pvRtrEv+95OTAfBgNVHSMEGDAWgBT1x0TcWRB4i9JnU5pv
+RtrEv+95OTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAKs024CvDYFv
+rj3GTXM8A9Jslg/86WukzEl/+PXDjbPljNV24RSsFVW5gO0ps6Q/EBkbllJP7xNO
+XmOUDyqUcvcwC1zzySqs8kJcF5GCuRXajy4KiEiA5VRmVUSShhnkYX7g1yXkhWrP
+Ps1fQArqHx84+naFSh9kVqu54QIykS7z
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.pk8
new file mode 100644
index 0000000..c8d2793
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.x509.pem
new file mode 100644
index 0000000..22b6148
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.x509.pem
@@ -0,0 +1,93 @@
+-----BEGIN CERTIFICATE-----
+MIIQ+zCCCOOgAwIBAgIJAOd3bpikuRKvMA0GCSqGSIb3DQEBDQUAMBQxEjAQBgNV
+BAMMCXJzYS0xNjM4NDAeFw0xNjA0MDQxOTM0MzFaFw00MzA4MjExOTM0MzFaMBQx
+EjAQBgNVBAMMCXJzYS0xNjM4NDCCCCIwDQYJKoZIhvcNAQEBBQADgggPADCCCAoC
+gggBALDYs7aIK08pNr9fdrpLmUVfSc+3n/RNU2e7o3fzwQf2IMExk/ZmxF/ORgAd
+pXPEkn7uOLYSp+fJHUgqsca+8HsxTN1ypKov0X3OeFbnBLXmsoXgjRzaMEgluupd
+B81xnAKE/Vb+HYaEJ4YP+3UgBLIItnwLtL6vdh+e4qQGF9KEAv+T+PdrNQF0EGWK
+weCaOuMKRKfSnNXMkgIgWgoEefsBXNOR/jRJVFxsnJlwsB2iw0FbKjrxnlmwBL+f
+A8YxdMoCLxjL0TuUEmRyd0jO7Td49kUIkW6ux/b4qOvcUPQiODXeayesJ1lmFepS
+ATjhgCz2+C3pcAJOPvOvC4v0+5OQ3YrU2kKsnj8G2ic3SdPUq4UUvQWqY+rCZVDH
+IqsEs/+XO++wMELkN3uiQcRIEO8aCug+VxMSRiyRSSNtxmcmedUZevbZ6+2leBtn
+AbLP33E5hC80A7WKuddQgOiA1yTUVxatZEaxHFVZlg2nzSYHipvwMVC2+zQ4yrKA
+mbNp5wiVUV5WLsUkYEuSwl+MG9vEjr2gTX+qLrvpIYS2AF/16SOEw5zQBPUcfVIz
+eJU+W//wwXdlNmA6qRCDXqLDBX1MQrChpaI2eRbv64k5C09LtEA5nt/lJt5dm8IF
+XpurOZqHTVG3CCS15SM8PyoApYKN0oM9+6Z+FDUOB+VbTW/hAqKYLNBJmNf8mRkK
++c1peoOAYw5iG8iaSD8f8bcIi3oFPMdt0Gs5vDoLjbWmK2s9P2wknA4hmVe7hvSy
+DMvyxj8j4BLadc3HafcXYPfoNPhfgoiZVLm6ijEj74iKeLSkef8F3x0Agulnitz3
+CWt7X6EXHbqR/0++VTqgnFDe+enf9oFzMsDDbOs59dpyGFSP159dTqJILimF5xUG
+Fw95hsTbdEblZ7Q2MiibB38ifz8WT+Pix72SnHrlcnKonv8Tkeoie0AP+dYkYXpC
+Dy0oIzl7Vhy1e99RjX8kKjZAfCuiQ7wnOGNu6V32UyKMvWD5E6mNLpsvyBRTxDhs
+ePpH5dZWbhg6WxhD68QG/Wi/8FRmc8/TPpPXilOG3HHtX6Q3yfGYHJB6/dJhWQQy
+iZawyEpcyZKjEyWoJayRsKSLb6gW6Idfc1Uf/yb6IHDRlYZEPF7JuznjLCaz2QC9
+8GCBGfUE9OGH+LtdMnsmn2IYEd1FtWrRGduG0HNKubmx8bJmc1HkYDQg3cksPb2o
+jwCND2ALGtTcR30yllmSmEJKpXBYB00iRvxvkBqCkL4THOXhN2V5uEMrS0r8GRZN
+QCvCoFKulPjITmlQ/ciVonN9y9qVeRbFE4ZxiiBxF41K/Mw45ugIqfg4ndJqbub6
+5p15nhYJIC2CbsVL5+1THmd+kompQhUo1ttwof0aHh3KLwe1uq2OEU7Tz71Ct5+G
+b5JjIAlQDuGcfsx3utJY3AE5ailtvaRNAz3FyTsZGkIOeqX4uswWltxGnuSMSbPi
+CPv7ngFXkytkK+3Oqs92XM8mhO1yqPzmm73+qZYDGFdy32C/Rr0enETmgkUFPToH
+28hMcOsEt+7L0GM6A5N708BaF9Csy7XTFz47Hk2CjaKTvP08Tl3bFPULrgJ5KCr6
+4hc/bVIDkU7c1lhDISJ1yuw4KHizmjuf4UeRBBDoB3MpPwZSeEkggGXuX1wkFApu
+RGhjCXQgFU9bNtUHM6Kj0tPQZrgsvx2wwBUFVOfPoej6afrJqpvep+EN1+OJCE4c
+AzuZ1CdE96vEleVbrq3BQaJbsm8JqHs7lAn1aiCK0semqAoXD4cT4L2H4E37IDlm
+PHsxIeTmgD7/TP3InuFB6sYvVM8moG1TLmtUJkpc8kkPBPNbTRHwuRvMGD1pSsP1
+aNbgKkEfGqL1iOrfoTCRGKDeDDxWGsxDOgW1hRs9wGzJuMQjl1Rlb11lnnX7UYyT
+UnD/yw7YaplScWwpsqntQewI59A4ad1wOJlabDUFwkD4i4ERTcjyea1ydE03qaOy
+0ItJbc8kjsEMWFAv1+y7/cxD7kALcytvBHhD8OVJ40qJrtwRsXnv2T74cTPh87qh
+3j2tjdJKVSLxwqg5ZdvIemnWmmFAPuRERResp5j5WLJcOFcXhbp4CAQLViRoktLf
+AKtgKSVa9FQLvombOq8GqWxqeGJEsq+8/X6UOj/RDPu8gUCdodmlxgC5BpJlMTfg
+9ElvHb4oRewPfc5MBV5i++8xagxS1+5NM6z+1qZfT+XJcJ/wFYyeSvGGdEgaDIVd
+XGqOFDmA20bUl0xWSM5j4At2CmymAn32i8FR5lNfB/f8tIGBlXQyrYzpAKoj6FrV
+3u43zKgYBzDTqNs61e+A8MScV5666gvpcOltFiaucc455JGiN2v7N+SAygWaX3nb
+jidmRaIAftup6kXVXxy1ZwpKCtUTqo0M+S/jO9clHy1EYaSX12blCL1B6OFpMRV7
+1foffUHwaPrMqqbPphgN4QRY2Ao2sKSliiP1T8s1T2iteEGiazCdWSOVVi9Acbo5
+DfeBlWwhW6OQpv1nMTznGscc4+ledP5yG5C6boz2aNwK6H6cpDfEc7tWTWhZN5Jm
+Jlra4pseqf9Lsc/Y4QMD1312C3Hu8EtJ/qlxEDhLnCW8PHxdlRsIkmcV8w+as/hu
+6/MlOYcCp9ae6nooFL7ZuDkdDWm84UXdce2ZVVGVoDa+RdpICnp79y/9CLxWue4H
+09VFEFUH//E6lOCBymUjTSO/DQ6z+ceb2W5B3WVV8gqADTDhAgMBAAGjUDBOMB0G
+A1UdDgQWBBQkHp1wX0Sfr0xz7xcip9UwEIFTLDAfBgNVHSMEGDAWgBQkHp1wX0Sf
+r0xz7xcip9UwEIFTLDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IIAQAd
+FhlHg4E7Yp8kIOfZRU5Cma6wbOSd2eHkV28WHGdwpKsvNhzgQEj+scYWSS8geozi
+vqSdJCoMmY8hWJh4SY0ED1DjPMoRvE8OotyGoCJovvYQia+gbVneT8JnfV3fkdwi
+hpUmAhokrsHkBj0jp2Ubff/D5yflA+QPCmhZZnkow+5QHXtmpy8CL9Fzfonz5uq7
+yCV5uWRicczFbQw3pDSXKn5OFqXuC8H/8R6Caq2TkJ1LusVtZJevcHBkEQ6e+XEX
+kZ+QCNtHw0a67LQEPtMXSyqZ/zR0roqwT6udUgHhdvZjbbb9GDpTW3u472IY18E+
+bf+npZl9kyuv2kyK1d2IjL45TxjBr7vLbjsP2UsmZvb3Wfb/kiMscvTBcxOL7/WA
+GNJ0XifmJWiDTDC+gUBC7LRN9lG8F7ykrMTtMUNlhow5LpIi0HA8TH58yq3/ulGq
+XWpculy33kcVAFTMGh57r8zq9DwkeW+RWggvHO2422S1bFGmKpizKASTvY6iqo4H
+yKvE9uZ41WaEbpp9WKPIaeup+ynxFpcgwMCKwvs7Yaj+mVexv7CoJ9nrEhMOHDxV
+GRyWDdBoIi08S02JHztZBXp5NZ+hqey5HrO4dhrnV1nVYJmH89KcAlXMfTZ2YHsv
+R2+dm6K8ToaX+Irqbz7Xbv8WG/aAdUqMSWkFEss7OT7VZBUiAdFaWqg0D0wtWSSE
+jZJJs9ISUTClq+97o9BEH2sAebchLFP56nY+Bj/zHBq2qPxTKdKE5BH13KcK1fwO
+eNn8a3SlSEHraa0oV6VjgSoMNdFz7b7b0r/Z8L4PEASJgH+VaGRm2TtuVWFHSqvX
+015UGITk6YgAQ25MTprJc/oAd0dut+aCPtOVElfukYvdrbw1YYQ9tc7kU+AVrzaf
+ytWj2GYR5Slfhle0inKlBvbpLTAHs82bp2Dgy9ZSQzW9/gIvLvCt+Hj0kiSYNcbX
+W7Ai5z2i6XKE7DdQO0Uzt+1bXGK3j2PI+81lCw2ejCFwjdYDWQw9f2nzQ5FgeYwG
+tc6fS4GbJM97n0yH9rj0Jb25AummZGnEL11ytPpC6Nv9cQdCuKDbaWQuQyRMCLEm
+hHaqV6k/fI4Etvuo15pyfJ9w7Xrhc6emgdg2HzJ99lDGkzZAF/3FR7N5pLPk5E0/
+PPlXUSiEx17IeWp3rNt0YSMixkGz+EbKyv9RIZzm/LV4zAzs2ZyUHHavUgZ602eg
+89ppqafaBrCwIWB1jUmnHJop9YlXQ3hE7pAV5qf9GxZLwUdzJcyLte1/vkn1yt94
+nLOZPPWUwUjIaBOZ7e/g8fHBjvAYwyoy3toKVpvkhR48NvcYD8pQ9cB6rIL0JkWV
+nQEYeISlJCUOO3K2eZ3ZH02ftha5gLshcGRXy9NS+4fNxDT3H+102RqSxmKPIxV0
+onV9RyOxUPKLRGjCZBZxs5aSxTYjFJ591azt3yAY4vwCnnHqdNGFbTat/Zc8LUOO
+J26n5cOYFGKPvZVvj8jMNYC1wo+R+A+1FeYXBV4MSVxCB7tjBlbU6OIyZSWLZ8Vw
+LMcPbuZ7ESj1LeTONwS1vspZM8Y/M8+RXv9VA8Z998tnNopdU3izVC2z6Zn9hNNI
+XBDbSe6ZRwsjXrm5TZCBgA4ZE18MwxPVhntSvl87Gc3wF4hz4BOiZXmffrXK4nQJ
+aVA8E2IsriCV+GQBN/ui+w3U9LbtsHrbauhjrru5EfYohpuInwvgPlAnTztdv9u7
+ee8RhwaCa+MInZanD6pRAAcfM6O64CPxHZtfVW6JM42N7wQXijvYzJPVR30F+6o1
+C+KwySuMBOGxOctmzLj938/OMrxuLBOmv3PJvSnHV0pWtbR7r7jH3v0uUm54zH56
+Qo/Rm/Aqf+m4Si3Xtsf9zvc89sqG5v2TT882Joja76zlJfaS31QgbnLTmKtAHtIC
+mqfQPvt1LNEJIiB6FZDHJIW5Ccm7imsixerxCBBoAt/J/dhW6N+cjZ0EWG5NiSoz
+9LmAZv8iWyqK/KvdPXUopQWqkYUvuIyNCYqzTRLKudUMohefNwghvl1gSGp4IMZ/
+4LyrJHi9eCcD9Z65PJsRTua+742N2sdhFfU/C4atOUGSK9x/Dl79Qkgsl6HqAoce
+HXiHAIvoOqC+jzEkjjxow30BzJeGsZoFwNvMUW7HcQ523DiIOx6MX8oQyKEo+W6C
+ayFvvvT3qHu2hL2ZxOXE+rGyUJnmwqctz4ChLvyYXa/eNrycs382x2U5XNXgXzNT
+3bwB9B+LnKSMJEB+UvHdbBcafYyevLptbF5xiiiUA0P3fq61AfmNiCzJWb+kaO11
+oHHQNWyG/fO49u3bZJkhvlsk8GXAp9uTqdW7YAqxjy8NohFewmtpTJPE62XKIqiq
++dqo4nUT761iaUBxgyj1v5jKcXT2JiEMnEe4AN7pZJ01pCNXQrXl+6ru4TVV3tpy
+OsDJ9UfZo8xZXEAJ/gvSyiih0xq6xhwGuUyExC3GldBz2frveWImxVEiqQIdHULH
+WwB6eAm9T1f+2hOGq7AB9Jb8CRyQniJWXtWu9uJBt+XwSt5lN6VUjeLt95SitvjO
+llqs0zhvTf52H8siwaO83Cui78iamqv7jVatB3JYW71S5cOyZ/x5Z5FYqKi8/wjO
+L4OyUs54kfcJllsxAmS014UgcTrJpbMNw7jSzLX6FxT4MEbyARK8wWQfEZQ2tCeo
+IOzfcYvlY05mG0KSzs6ZGBrWRZQDPcbJ0CKNSLTFbQ==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.pk8
new file mode 100644
index 0000000..105f7e7
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.x509.pem
new file mode 100644
index 0000000..0e7b38e
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.x509.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAeGgAwIBAgIJAI41MGzdARX3MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS0yMDQ4MB4XDTE2MDMzMTE0NTc0OVoXDTQzMDgxNzE0NTc0OVowEzER
+MA8GA1UEAwwIcnNhLTIwNDgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDQ4JI1EJ239V4wss0jpVlZMudh2/kARCVdoBgsRQuvc2RNnO23Eyynlt9UN+Dc
+NRdQIhbCpVTjdEl/bePECHlqg9NE3frAj5GebiUdWL6A/idKsZA1nAKyIgxxjcnu
++38OcrlO6XOm36euxGfd/ULrghZGXzMVFq4uLiIv3DqFkUcIlE0BvUiUoNwpopV4
+MKj1GQgoaEObJG5xkMBKO6vg36VfJ3s3V3r48uJxYGhhBZEB0EpoXLd4i0piAB8S
+MLb0Ek6wA/HZ8A2rdnStk1wl/83OM1jO0uB3hyfJpqIijlvNGnrloYyyOIqS0LGH
+nxSJD7goASH2Ef0h4yxbsOvHAgMBAAGjUDBOMB0GA1UdDgQWBBQXAi1zEH84mzkS
+62ohswGGWSwdbzAfBgNVHSMEGDAWgBQXAi1zEH84mzkS62ohswGGWSwdbzAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAB92T5toLkF6dLl65/boH5Qvub
+5wfIk0AD12T3t3kYWQFOH0YDCHNL3SfmrjYM/CwNJAd1KuCL5AZcn0km/n0SFXt5
+8Ps/MBcb0eK1fYezeEehKUyt5IBgDTKeQOel6So8rGuQRrDf/WV8rt6fugkIODFx
+sB3oj4ESaGXbvmvWD6q4a3koq/nV26kALchnAr7/FTNq3HEIQ1BDr9pldVh1gEV/
+ohHKcQP4M22Es7lredzpIcb5K6Ko/UtwsSRtHnoOjwmb+L/FsgAJsekmcJG5TK1X
+ciIsrrNFDCYzf/d9O1PD/V95kB7460qMzrGWZpc3mLe+OnmVMq6c4omOtIKl
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.pk8
new file mode 100644
index 0000000..163e06c
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.x509.pem
new file mode 100644
index 0000000..0f3cd14
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.x509.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID+TCCAmGgAwIBAgIJAN8aZ+YVywdhMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS0zMDcyMB4XDTE2MDMzMTE5MTQ1OFoXDTQzMDgxNzE5MTQ1OFowEzER
+MA8GA1UEAwwIcnNhLTMwNzIwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIB
+gQCcgu3kzCLVWeUzwO5vhwWFD4rCJVavnVJjA4hz3fg9wsh8wpK0D39a8iyKS714
+5fFF/EsPpoKo6b8l9GVHfrSzJSa0rMcQ7+GHLyfG+8Wt6cnGwb8m6FOMKM8YAlUO
+zVL/WDZXBGvHu/gmZXM0ZbCy1cFBy5/kcGF2zF/fa+a8n4fUiQlbGC6y5iXKewMF
+z5/tFN4BeShBSNxGJVNOut/bLOvpGoPQVsteFlUgiSOPuXeiMeXDDEMEHbY7u7lB
+Fmjs5yAdXaLtnsJD689NdfIDZYHsiBRf7sFNWWNg4gE0gEPhN0QkC2Bkak80t2Mw
+XNakB7gqJ7Vsy+ZPBmhzMzeZbrK9cZXgqNNlxmraHycGzPif4sqmpy1/xFxNqOQh
+n2cc0fd2RG0ql1T4qO0U2b2NQzNMcgrtBW2E1UUUVukVJLCa7RKyt7yq7uUqeCYd
+MxNfvWYBSCzpZMvTI7jq6HcCqQOfW8nkE/z2IBdWvBi3yIdgKSsW0uZsW2/1+KlJ
+fhkCAwEAAaNQME4wHQYDVR0OBBYEFLGsv+jET2b4cWyINayy3qf/U7izMB8GA1Ud
+IwQYMBaAFLGsv+jET2b4cWyINayy3qf/U7izMAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggGBACLyVVZrgLXL0PUAS2WwZruWj9q7lVnzLMla3u9j/fSLnlPK
+/YcuQh/DqovNkPjFrItww4VfLxkQNsdOccAMHWA2rnWivOYnS1q3gM56e9KN/fEq
+yRc3ltZCPvEoFnFEVtVfmgZJGV0xBLZUFHnPjlWtUYXS8pR89x/Klwy5aaJ9OcGW
+SPaI0I3TyFHCb92Dtfdehtdu8YCDrwTyaYLHvYdNQFDrJ20I8WNsG8RwklfAWNwZ
+IJ5fQxwHiCKxvdaTt2NYUSm4R4kEQCgklrgnaEy2kzDVKp4GjQwVrsa1btK+Srrd
+gtIqB+azx3XziuLi129qJGeZsof8ylN5eYmw0r57d6OPB/xj3roBsB77t4d5jEhl
+Y0BZ93t2HWvXJmuolf1JcauDOcGhxxgdiWdcOWeSABH3cNUiilRfs8HRwSzZwB5E
+RyjvKBdGirUAbLgri+8t9165gaz3wVhP4xkcD4e6LoupWHarAMKunMVGVbCOj7mj
+AUPHJ3Z+HhUKiI/q9g==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.pk8
new file mode 100644
index 0000000..0f498e5
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.x509.pem
new file mode 100644
index 0000000..704dcbd8
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.x509.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE+TCCAuGgAwIBAgIJAIhxrQmG+dcZMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS00MDk2MB4XDTE2MDMzMTE1Mjg0NloXDTQzMDgxNzE1Mjg0NlowEzER
+MA8GA1UEAwwIcnNhLTQwOTYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQDTPhE7i4Bv3BQG1ifMPZfTGA1ZvE+mQWOgQ1q/3AQz23I8pIaoj1wFbYDvnTYG
+UCDnlJqKvwL4mrAnxvqTxm+0g/WFOoBKFoNY5OhgcDfomNEFQajY9bgXaNiwEYDU
+0X+q+2KAnr35MF7vdEaHcN8gFh15wObVXmlerMIOWejnwrM4MOXjGjNXtiB+Dg04
+Fb9eHufZ+s1dKNAojD08mUJkxTC1gjmBKPr8hOAPo9ay5NZk6mGaI1E0U5NbIpDe
+0EhYxRXkDjP7f6BzbhFEupCOzZNMC5CxD8fsmku1CaKBayGpsxktYFxsw1RFVTZj
+3pKYnM1fJBHj/hU+7zy60MZNpdU6i5HVa8FPldwAxv6P2dz0wIl9S3rrqDrd2/1p
+r3rKNrMbVo7wzZ8euVhmjttsRvN8NykCniX6oWxuX7EFQxT/ZM0xk055gMMW7xbr
+oLtPAJ1Lk7R6aTCS+ObrhBgS8+38sIT8rF/CCz2KQ68iUpMmMBz+dkYsDwHPq7vG
+wIy8J7fwzTLqUbyO971+4MD9/9HbqfjRAsjfnSz8HqfyHrSDKeAhgqlr8j8DtQ7X
+B2PIZIEmyN//A13xfZQ63c/KR/yf9nPig4KfHulODfWXBD+2T5kzakTSn4My37FF
+mzG0giMMJ3zGs4QpGZAKFGdwhUq6nAAqEKYo+dptlFhbzQIDAQABo1AwTjAdBgNV
+HQ4EFgQU+f3rdfojsysUqNHmjE4c+0I8YGUwHwYDVR0jBBgwFoAU+f3rdfojsysU
+qNHmjE4c+0I8YGUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAbOd0
+bKbaeGNsinFSck4niiHDhkeD7GhsneReA73LDJVwAsr5SLAYlmZL/R+1Jw2FGa5m
+82q8412xoVxqAbsz/OrBjoW+5RjAUpHSv0vo3Ny9EpFDpRI1yO8EFU2PhpbcC8Av
+101/oBA8tgKDKgb9H9GrnuqKqxLvrOKDle0TEWAb4X+yyuLSneU6UZTn/g6hhKMw
+pRcsCkwwKa2266auq93NA30Xb1UME5med/5fBKzjL7TvA8BTbr8EdHxjbPmnyI1n
+iVQJnkvvk6rDRcWeOt+lP/pmvaCcVFp9FJHlWmxrus7x0PuH8WxecVl6PeV3MLyR
+HXwGLzlqJWFm753FP3sTV3xNqemo1IhtlHR3jgU8Y7Ixq2Ljjs5izucqM+u2Ioo/
+wbzlhjfRmxqGE3RWvq6Vv5C22Th3hEA7PDUKAh1/cvUwZxOh1Wa9Nedhy0SUXAR8
+nY2GHJEN6QmR1ZAoyABHuPqk1IjduDONo0usGk/iYIFMgfwitc5Tv4gdjjBLburF
+NRU3QkoT1twPueb4Xnvmb/yHmTmqm7MM4OlkmTSpYRci8C1JNChdqIjNSF36Flnm
+DEMqP6petbkZcORD7UtgoB+DCPyBWybtm/GDOW2v3CWo94Q5A1yRDpqyQOTIJChe
+sssLUtp3bfmTSFFMfmsovynUlFpsazeFKjQOkYQ=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.pk8
new file mode 100644
index 0000000..cc7a7ec
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.x509.pem
new file mode 100644
index 0000000..42f1428
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.x509.pem
@@ -0,0 +1,50 @@
+-----BEGIN CERTIFICATE-----
+MIII+TCCBOGgAwIBAgIJAMMCN6DTJaAOMA0GCSqGSIb3DQEBDQUAMBMxETAPBgNV
+BAMMCHJzYS04MTkyMB4XDTE2MDQwNDE5MzI0NloXDTQzMDgyMTE5MzI0NlowEzER
+MA8GA1UEAwwIcnNhLTgxOTIwggQiMA0GCSqGSIb3DQEBAQUAA4IEDwAwggQKAoIE
+AQCt2gaOPSTn1A/WkapaytoE2RGF5nBzlfLocagG+0Bgz0RH3QQq0xBEmQivmbj4
+egyKFQQ9dYrefXRnayLQvHpfeT31QXR3iKOfMnvtxK9UnkXo9S/T+czyj91Ox51w
+HFUyMlXjFs8btxi6Lpkrgl3jmL+e4/WI8khvTrdszrO8rBHBYlD8Y7SAvPcVczYq
+nn4m6Jd0/abR5slHiyGtkTREoHmW/u4r4PfTzanLyzcsWH9/td+sYHcu1Y0XTWTR
+x2qrUmpD+7X5cvXP9rsECU82dtnyPZPIHBqzfLJ8oGELsJxgVZ0u9gW0tlmJQdVo
+Q0QPJSWivnNxPl1czJYbXimbY3Zh5hCzdyNqQewVx6iNsNh008JsXJ5/yvJQgLgZ
+UR2gWZMGzLc4V2wiqxuLzELt5RoXPehAdAiOLQu/3Fw+u4J/d7NEwpKgpdDGyG/U
+9nV6mjvomcgOdWKblaRAeiXauYy/MgW68kIu4O4SoKWRRmOF2p+tch3aDKw9M89O
+88QhEzbzDsioAxeOAqL7th3bSPZ2fX05xtM2vFK71QFM41q+FOL+062Ev/VJyU4g
+kxK643V+Cxso9CZEVtFfkNnVIGOI2h8knkOiLtbMnCx/hcxuZLm/XvYQxOO/7ScL
+rkHLUuKu/dK2ksDn8yBgaHfVlHkMmVoSll6fKB+UXpPX7xClrGQAFpVUji5oZN0s
++EcMQdcMtsb6LxnwC9XS1ELQ5FQGuJFatwY9RSV3cbwI6kNKaZiB5sDDAaAHX9GU
+U3EA2fm0u+4UFOSSmYTfx/jl0V1NMQ1oOAY9QMqzckMo2y9cepLQ3temQ/k4bNqj
+rYB3POdqS9OoT74UKU8gg9rv01PaFlLHhPKwVc+MjY36aVefbfk1KZzBpm2twUUm
+F0kz4pU3BYj0aSrTeKWaTLjdn4ndGMSe3QMQQ5GUchWCcygTyID8Wx8+eDzPIs/U
+sc++7fQRuPawcd11oQ7wTjWIjr7VnsV8hiHSyMupEad8HuBt8CNtDf/m/hD1LsEf
+0dY8nDGSPvV/ih2YqTfhcac65D4JKKbV5x65aEwM7frYwi9QsB7CK2xLMHnatp2a
+TRcA24VEsaBP2+UNSLyxkOeeuzSCksHLPBWkVfcRbKUeD9x4Dtwf2WsUtYjGzOQ7
+ApLBB4XHe+GPr/i+PmJP4IDoU1Mifbjla8rz2ZuebZgPnyV7nSvkG/FUqUYpa3Ut
+LY0nF/2dDRF0NirbWuB4Mkk/KlxCQ3w8EZFY5u6L/ee23WxbnVOEQJBtKh7/I/UV
+2dGqoVJx2UqT0MpjUCFjx+KjWvaEt+FfmjfRRqQfHLkJlYly/YdeUrGPdGgJNr0C
+csnZkAZmKDo4OVv+wVduHxHfAgMBAAGjUDBOMB0GA1UdDgQWBBRdiMpGc1L++yQc
+MtftoeGuLwJ+PzAfBgNVHSMEGDAWgBRdiMpGc1L++yQcMtftoeGuLwJ+PzAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IEAQBo9lUFyV8jI0IpcQLC7hC0ILxx
+6DsDw/YpMd9lRyujKa//OVJOEO3Z+SalfoLslMPCD1eeJBxgx9/xTMxZUrunOMJu
+Ddxc5RypVwdt6NOUQ3pNYU+Qkp73aZzakm6/i1LQDOxGf1PaZooPqXaKMfyb9CQ+
+M5wR9XsLDAyQPlylft3cWsp7DaPsrcp7Sn5u33TtvCDgfMwbKZrzzmCdAHS52p0A
+czMpDgYxhxCuHPwN6XSAxlrWnfpkOsdKneiVr4aDm1fp61PQg+sOKNCNJCMmUB50
+XFj14qLmvjLERNl2vUfDqoj6DxC9OceioZljzFM2d8/DEC1/YUT8AGYZQt0ISLlq
+QW4e4iIxXxVNKwXvJZMCd3z4XX8SvAOXL0+WrOffgkQQpSr2jBXKFe0BpCUnzVkN
+jw/bVJ89jrqfupExJ6kKTLzI+H2u/7LgZUn9/QlvhWR3IL1nEvCCOPHXTreuUp2U
+KauH7WQU+mzF/K+obzYiaPc53dz0C3JcvWgv5cBbhDUsGsziZLPkR3r5TvpTNF3t
+c3Ky84q7CfOKI+hGN/S+BNSv+TdA5uOG+h8GJ6SAwVpimzguhx2/iRg7OiHmhoy4
+UfsCF/QdoF3cEoSMMzorOIM+szZ+XggJMbtWzIv4NAL2TCKJcpB6t0Uxci6JN6lM
+tnbq78QxeOoJ3D3g6ZQoGvCdKwHcMQunS2MK75j9hckX5hR+0xnH++bI+D3qXaul
+zCOAcMoGpM7WgyzAc3mh9aAJFk1J9OYzpFY34nX2cDMc0xtI2s9p2/8X14ir5suK
+R0rqm3BZewDaQVNtrZCm/sch1I0cN4GomvxZ+2xD43vsZm8QEB2fyTvazg6kW2O9
+G0coUmszwI63f7fVx+wzZZxS24N17lIO36hjBq12SKDz9C3cIOZpPYdcaNxDyiwq
++RojbgUnosJji+xZtyK5Bf1kNB+jNoNT5OrWCXCR62Z5CQ+fAdlz4NPdibYnwscF
+SD8OA2I7UIT42KAuDBEMKVXe4SlhqLzOdqXwZ7h/ZxyUlY+zpwLO9vfLVpqZiavl
+bx+RO7lkvxPGEtM4mjXt5dNx2rgML/lXSE63qaqspYLJ806A3GE0918/b+ZDfvzG
+HLbeqIVtAlXwOGFLdifLvsgFybQ5yriR/yTlHXN/T8K+Q6wPo3uNkKNgUDq0FmzF
+N9UDQ+VFAdwaGPfBox3okGPoD6/HdiokuwZm4mlioHjZc513qhDapS3fJcXV6tu9
+OhIPBJ5NXVw3IVXwB+eskd2W5y8QlHZKBNTwzc/PBqL93QA2PxOFispDtevAuyTq
+OhRConYsMhoLf/9NqhEsyKVhwtYhYrUh0Q+hCiAg+YpjKuE2YJoUNMVyF3dY
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/README.txt b/hostsidetests/appsecurity/res/pkgsigverify/README.txt
new file mode 100644
index 0000000..fca2b11
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/README.txt
@@ -0,0 +1,3 @@
+APKs in this directory are used by PkgInstallSignatureVerificationTest.
+See that class for information about how these APKs were generated.
+
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/original.apk b/hostsidetests/appsecurity/res/pkgsigverify/original.apk
new file mode 100644
index 0000000..2993c2cc
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/original.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/two-signers-second-signer-v2-broken.apk b/hostsidetests/appsecurity/res/pkgsigverify/two-signers-second-signer-v2-broken.apk
new file mode 100644
index 0000000..fcf154e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/two-signers-second-signer-v2-broken.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/two-signers.apk b/hostsidetests/appsecurity/res/pkgsigverify/two-signers.apk
new file mode 100644
index 0000000..f11760f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/two-signers.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-two-signers.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-two-signers.apk
new file mode 100644
index 0000000..f096a56
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-two-signers.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-1024.apk
new file mode 100644
index 0000000..0f0f016
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-2048.apk
new file mode 100644
index 0000000..aa30612
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-3072.apk
new file mode 100644
index 0000000..68edee9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-1024.apk
new file mode 100644
index 0000000..938ea7a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-2048.apk
new file mode 100644
index 0000000..2f0002f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-3072.apk
new file mode 100644
index 0000000..13b4bcb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-1024.apk
new file mode 100644
index 0000000..b1bf280d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-2048.apk
new file mode 100644
index 0000000..8e7415f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-3072.apk
new file mode 100644
index 0000000..65f8238
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-1024.apk
new file mode 100644
index 0000000..f5db0e4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-2048.apk
new file mode 100644
index 0000000..d18a9a9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-3072.apk
new file mode 100644
index 0000000..641ba50
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-1024.apk
new file mode 100644
index 0000000..dd8ab61
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-2048.apk
new file mode 100644
index 0000000..129a335
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-3072.apk
new file mode 100644
index 0000000..41287d7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p256.apk
new file mode 100644
index 0000000..e9a0d90
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p384.apk
new file mode 100644
index 0000000..848cda0
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p521.apk
new file mode 100644
index 0000000..397e6db
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p256.apk
new file mode 100644
index 0000000..5127d60
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p384.apk
new file mode 100644
index 0000000..b5d9d46
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p521.apk
new file mode 100644
index 0000000..f3aa1d6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p256.apk
new file mode 100644
index 0000000..02b8a31
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p384.apk
new file mode 100644
index 0000000..5c4bf7b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p521.apk
new file mode 100644
index 0000000..3a91ee5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p256.apk
new file mode 100644
index 0000000..ec4a42e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p384.apk
new file mode 100644
index 0000000..c3c3e0a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p521.apk
new file mode 100644
index 0000000..5be8ac5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p256.apk
new file mode 100644
index 0000000..60090a5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p384.apk
new file mode 100644
index 0000000..63f6780
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p521.apk
new file mode 100644
index 0000000..53ae508
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-1024.apk
new file mode 100644
index 0000000..fe50da7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-16384.apk
new file mode 100644
index 0000000..3ce1737
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-2048.apk
new file mode 100644
index 0000000..5eb6dec
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-3072.apk
new file mode 100644
index 0000000..451f336
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-4096.apk
new file mode 100644
index 0000000..a99a670
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-8192.apk
new file mode 100644
index 0000000..10f4654
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-1024.apk
new file mode 100644
index 0000000..f31e649
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-16384.apk
new file mode 100644
index 0000000..784e569
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-2048.apk
new file mode 100644
index 0000000..a2801e5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-3072.apk
new file mode 100644
index 0000000..8d9fccf
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-4096.apk
new file mode 100644
index 0000000..3e36a40
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-8192.apk
new file mode 100644
index 0000000..b8f979d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-1024.apk
new file mode 100644
index 0000000..d86ac4d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-16384.apk
new file mode 100644
index 0000000..7656ece
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-2048.apk
new file mode 100644
index 0000000..4971db7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-3072.apk
new file mode 100644
index 0000000..ed7f3f5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-4096.apk
new file mode 100644
index 0000000..7d47560
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-8192.apk
new file mode 100644
index 0000000..99bcba2
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-1024.apk
new file mode 100644
index 0000000..46d3e61
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-16384.apk
new file mode 100644
index 0000000..21bf67f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-2048.apk
new file mode 100644
index 0000000..a952f1b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-3072.apk
new file mode 100644
index 0000000..db6941d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-4096.apk
new file mode 100644
index 0000000..5bd3d0d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-8192.apk
new file mode 100644
index 0000000..d8630b6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-1024.apk
new file mode 100644
index 0000000..9438016
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-16384.apk
new file mode 100644
index 0000000..bb0caf0
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-2048.apk
new file mode 100644
index 0000000..81a0258
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-3072.apk
new file mode 100644
index 0000000..b76d7cf
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-4096.apk
new file mode 100644
index 0000000..2583f6f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-8192.apk
new file mode 100644
index 0000000..f0b47f6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-1024.apk
new file mode 100644
index 0000000..7c6ff19
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-16384.apk
new file mode 100644
index 0000000..8cf9eba
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-2048.apk
new file mode 100644
index 0000000..58676e8
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-3072.apk
new file mode 100644
index 0000000..2f4b23c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-4096.apk
new file mode 100644
index 0000000..b823de3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-8192.apk
new file mode 100644
index 0000000..ffa6be1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk
new file mode 100644
index 0000000..a194a2c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-apk-sig-block-size-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-apk-sig-block-size-mismatch.apk
new file mode 100644
index 0000000..e657a80
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-apk-sig-block-size-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-cert-and-public-key-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-cert-and-public-key-mismatch.apk
new file mode 100644
index 0000000..5fbe97e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-cert-and-public-key-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-garbage-between-cd-and-eocd.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-garbage-between-cd-and-eocd.apk
new file mode 100644
index 0000000..9360383
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-garbage-between-cd-and-eocd.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-missing-classes.dex.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-missing-classes.dex.apk
new file mode 100644
index 0000000..0f1350a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-missing-classes.dex.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-no-certs-in-sig.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-no-certs-in-sig.apk
new file mode 100644
index 0000000..692c6b3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-no-certs-in-sig.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-signatures-and-digests-block-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-signatures-and-digests-block-mismatch.apk
new file mode 100644
index 0000000..fb397a4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-signatures-and-digests-block-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-truncated-cd.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-truncated-cd.apk
new file mode 100644
index 0000000..d2e3e8d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-truncated-cd.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers.apk
new file mode 100644
index 0000000..697b046
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-unknown-pair-in-apk-sig-block.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-unknown-pair-in-apk-sig-block.apk
new file mode 100644
index 0000000..a506bfb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-unknown-pair-in-apk-sig-block.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk
new file mode 100644
index 0000000..18a4409
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024.apk
new file mode 100644
index 0000000..9c8232f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-2048.apk
new file mode 100644
index 0000000..1d679b1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-3072.apk
new file mode 100644
index 0000000..6921479
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk
new file mode 100644
index 0000000..4cfc49c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk
new file mode 100644
index 0000000..0339d39
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256.apk
new file mode 100644
index 0000000..657f1f9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p384.apk
new file mode 100644
index 0000000..326c681
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p521.apk
new file mode 100644
index 0000000..7fcb887
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p256.apk
new file mode 100644
index 0000000..5942916
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p384.apk
new file mode 100644
index 0000000..82aa6ad
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p521.apk
new file mode 100644
index 0000000..fde4294
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ignorable-unsupported-sig-algs.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ignorable-unsupported-sig-algs.apk
new file mode 100644
index 0000000..165b262
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ignorable-unsupported-sig-algs.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-1024.apk
new file mode 100644
index 0000000..5751fbe
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-16384.apk
new file mode 100644
index 0000000..a832366
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk
new file mode 100644
index 0000000..fe6be6f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
new file mode 100644
index 0000000..90ab764
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-3072.apk
new file mode 100644
index 0000000..a3569d6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
new file mode 100644
index 0000000..101602a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-8192.apk
new file mode 100644
index 0000000..1c9f131
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-1024.apk
new file mode 100644
index 0000000..e95e312
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-16384.apk
new file mode 100644
index 0000000..2b332b1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-2048.apk
new file mode 100644
index 0000000..5e5863e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-3072.apk
new file mode 100644
index 0000000..d587865
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk
new file mode 100644
index 0000000..72f5dba
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096.apk
new file mode 100644
index 0000000..1189d8a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-8192.apk
new file mode 100644
index 0000000..146534e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-1024.apk
new file mode 100644
index 0000000..1331d35
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-16384.apk
new file mode 100644
index 0000000..a205741
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk
new file mode 100644
index 0000000..f90d226
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048.apk
new file mode 100644
index 0000000..8bdfb45
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-3072.apk
new file mode 100644
index 0000000..d36731c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-4096.apk
new file mode 100644
index 0000000..8e190b4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-8192.apk
new file mode 100644
index 0000000..c879ffe
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-16384.apk
new file mode 100644
index 0000000..d398584
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-2048.apk
new file mode 100644
index 0000000..bf8150d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-3072.apk
new file mode 100644
index 0000000..ca11ebb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-4096.apk
new file mode 100644
index 0000000..dfa1206
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-8192.apk
new file mode 100644
index 0000000..1bdd017
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-wrong-apk-sig-block-magic.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-wrong-apk-sig-block-magic.apk
new file mode 100644
index 0000000..85750d4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-wrong-apk-sig-block-magic.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped-with-ignorable-signing-schemes.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped-with-ignorable-signing-schemes.apk
new file mode 100644
index 0000000..634255b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped-with-ignorable-signing-schemes.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped.apk
new file mode 100644
index 0000000..0d04d93
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
new file mode 100644
index 0000000..ad68017
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Set of tests that verify behavior of direct boot, if supported.
+ * <p>
+ * Note that these tests drive PIN setup manually instead of relying on device
+ * administrators, which are not supported by all devices.
+ */
+public class DirectBootHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+ private static final String TAG = "DirectBootHostTest";
+
+ private static final String PKG = "com.android.cts.encryptionapp";
+ private static final String CLASS = ".EncryptionAppTest";
+ private static final String APK = "CtsEncryptionApp.apk";
+
+ private static final String OTHER_APK = "CtsSplitApp.apk";
+ private static final String OTHER_PKG = "com.android.cts.splitapp";
+ private static final String OTHER_CLASS = ".SplitAppTest";
+
+ private static final String MODE_NATIVE = "native";
+ private static final String MODE_EMULATED = "emulated";
+ private static final String MODE_NONE = "none";
+
+ private IAbi mAbi;
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ public void setAbi(IAbi abi) {
+ mAbi = abi;
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ assertNotNull(mAbi);
+ assertNotNull(mCtsBuild);
+
+ getDevice().uninstallPackage(PKG);
+ getDevice().uninstallPackage(OTHER_PKG);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ getDevice().uninstallPackage(PKG);
+ getDevice().uninstallPackage(OTHER_PKG);
+ }
+
+ /**
+ * If device has native FBE, verify lifecycle.
+ */
+ public void testDirectBootNative() throws Exception {
+ if (!isSupportedDevice()) {
+ Log.v(TAG, "Device not supported; skipping test");
+ return;
+ } else if (!MODE_NATIVE.equals(getFbeMode())) {
+ Log.v(TAG, "Device doesn't have native FBE; skipping test");
+ return;
+ }
+
+ doDirectBootTest(MODE_NATIVE);
+ }
+
+ /**
+ * If device doesn't have native FBE, enable emulation and verify lifecycle.
+ */
+ public void testDirectBootEmulated() throws Exception {
+ if (!isSupportedDevice()) {
+ Log.v(TAG, "Device not supported; skipping test");
+ return;
+ } else if (MODE_NATIVE.equals(getFbeMode())) {
+ Log.v(TAG, "Device has native FBE; skipping test");
+ return;
+ }
+
+ doDirectBootTest(MODE_EMULATED);
+ }
+
+ /**
+ * If device doesn't have native FBE, verify normal lifecycle.
+ */
+ public void testDirectBootNone() throws Exception {
+ if (!isSupportedDevice()) {
+ Log.v(TAG, "Device not supported; skipping test");
+ return;
+ } else if (MODE_NATIVE.equals(getFbeMode())) {
+ Log.v(TAG, "Device has native FBE; skipping test");
+ return;
+ }
+
+ doDirectBootTest(MODE_NONE);
+ }
+
+ public void doDirectBootTest(String mode) throws Exception {
+ int[] users = {};
+ try {
+ users = createUsersForTest();
+
+ // Set up test app and secure lock screens
+ new InstallMultiple().addApk(APK).run();
+ new InstallMultiple().addApk(OTHER_APK).run();
+
+ // To receive boot broadcasts, kick our other app out of stopped state
+ getDevice().executeShellCommand("am start -a android.intent.action.MAIN"
+ + " -c android.intent.category.LAUNCHER com.android.cts.splitapp/.MyActivity");
+
+ // Give enough time for PackageManager to persist stopped state
+ Thread.sleep(15000);
+
+ runDeviceTests(PKG, CLASS, "testSetUp", users);
+
+ // Reboot system into known state with keys ejected
+ if (MODE_EMULATED.equals(mode)) {
+ getDevice().executeShellCommand("sm set-emulate-fbe true");
+ getDevice().waitForDeviceOnline();
+ } else {
+ getDevice().rebootUntilOnline();
+ }
+ waitForBootCompleted();
+
+ if (MODE_NONE.equals(mode)) {
+ runDeviceTests(PKG, CLASS, "testVerifyUnlockedAndDismiss", users);
+ } else {
+ runDeviceTests(PKG, CLASS, "testVerifyLockedAndDismiss", users);
+ }
+
+ } finally {
+ try {
+ // Remove secure lock screens and tear down test app
+ runDeviceTests(PKG, CLASS, "testTearDown", users);
+ } finally {
+ getDevice().uninstallPackage(PKG);
+ removeUsersForTest(users);
+
+ // Get ourselves back into a known-good state
+ if (MODE_EMULATED.equals(mode)) {
+ getDevice().executeShellCommand("sm set-emulate-fbe false");
+ getDevice().waitForDeviceOnline();
+ } else {
+ getDevice().nonBlockingReboot();
+ }
+ waitForBootCompleted();
+ }
+ }
+ }
+
+ private int[] createUsersForTest() throws DeviceNotAvailableException {
+ // TODO: enable test for multiple users
+ return new int[] { 0 };
+// return Utils.createUsersForTest(getDevice());
+ }
+
+ private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
+ Utils.removeUsersForTest(getDevice(), users);
+ }
+
+ private void runDeviceTests(String packageName, String testClassName, String testMethodName,
+ int... users) throws DeviceNotAvailableException {
+ for (int user : users) {
+ Log.d(TAG, "runDeviceTests " + testMethodName + " u" + user);
+ Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName, user);
+ }
+ }
+
+ private String getFbeMode() throws Exception {
+ return getDevice().executeShellCommand("sm get-fbe-mode").trim();
+ }
+
+ private boolean isBootCompleted() throws Exception {
+ return "1".equals(getDevice().executeShellCommand("getprop sys.boot_completed").trim());
+ }
+
+ private boolean isSupportedDevice() throws Exception {
+ final String featureList = getDevice().executeShellCommand("pm list features");
+ if (featureList.contains("feature:android.hardware.type.watch\n") ||
+ featureList.contains("feature:android.hardware.type.television\n")) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private void waitForBootCompleted() throws Exception {
+ for (int i = 0; i < 45; i++) {
+ if (isBootCompleted()) {
+ Log.d(TAG, "Yay, system is ready!");
+ return;
+ }
+ Log.d(TAG, "Waiting for system ready...");
+ Thread.sleep(1000);
+ }
+ throw new AssertionError("System failed to become ready!");
+ }
+
+ private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+ public InstallMultiple() {
+ super(getDevice(), mCtsBuild, mAbi);
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
new file mode 100644
index 0000000..f6c6f18
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Locale;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Tests for APK signature verification during installation.
+ */
+public class PkgInstallSignatureVerificationTest extends DeviceTestCase implements IBuildReceiver {
+
+ private static final String TEST_PKG = "android.appsecurity.cts.tinyapp";
+ private static final String TEST_APK_RESOURCE_PREFIX = "/pkgsigverify/";
+
+ private static final String[] DSA_KEY_NAMES = {"1024", "2048", "3072"};
+ private static final String[] EC_KEY_NAMES = {"p256", "p384", "p521"};
+ private static final String[] RSA_KEY_NAMES = {"1024", "2048", "3072", "4096", "8192", "16384"};
+ private static final String[] RSA_KEY_NAMES_2048_AND_LARGER =
+ {"2048", "3072", "4096", "8192", "16384"};
+
+
+ /** Device under test. */
+ private ITestDevice mDevice;
+
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDevice = getDevice();
+ assertNotNull(mCtsBuild);
+ uninstallPackage();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ uninstallPackage();
+ } catch (DeviceNotAvailableException ignored) {
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testInstallOriginalSucceeds() throws Exception {
+ // APK signed with v1 and v2 schemes. Obtained by building
+ // cts/hostsidetests/appsecurity/test-apps/tinyapp.
+ assertInstallSucceeds("original.apk");
+ }
+
+ public void testInstallV1OneSignerMD5withRSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-md5-%s.apk", RSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA1withRSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha1-%s.apk", RSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA224withRSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha224-%s.apk", RSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA256withRSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA384withRSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha384-%s.apk", RSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA512withRSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA1withECDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-ecdsa-sha1-%s.apk", EC_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA224withECDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-ecdsa-sha224-%s.apk", EC_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA256withECDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA384withECDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-ecdsa-sha384-%s.apk", EC_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA512withECDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA1withDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-dsa-sha1-%s.apk", DSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA224withDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-dsa-sha224-%s.apk", DSA_KEY_NAMES);
+ }
+
+ public void testInstallV1OneSignerSHA256withDSA() throws Exception {
+ // APK signed with v1 scheme only, one signer.
+ assertInstallSucceedsForEach("v1-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES);
+ }
+
+// Android platform doesn't support DSA with SHA-384 and SHA-512.
+// public void testInstallV1OneSignerSHA384withDSA() throws Exception {
+// // APK signed with v1 scheme only, one signer.
+// assertInstallSucceedsForEach("v1-only-with-dsa-sha384-%s.apk", DSA_KEY_NAMES);
+// }
+//
+// public void testInstallV1OneSignerSHA512withDSA() throws Exception {
+// // APK signed with v1 scheme only, one signer.
+// assertInstallSucceedsForEach("v1-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES);
+// }
+
+ public void testInstallV2StrippedFails() throws Exception {
+ // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using
+ // zipalign).
+ // This should fail because the v1 signature indicates that the APK was supposed to be
+ // signed with v2 scheme as well, making the platform's anti-stripping protections reject
+ // the APK.
+ assertInstallFailsWithError("v2-stripped.apk", "Signature stripped");
+
+ // Similar to above, but the X-Android-APK-Signed anti-stripping header in v1 signature
+ // lists unknown signature schemes in addition to APK Signature Scheme v2. Unknown schemes
+ // should be ignored.
+ assertInstallFailsWithError(
+ "v2-stripped-with-ignorable-signing-schemes.apk", "Signature stripped");
+ }
+
+ public void testInstallV2OneSignerOneSignature() throws Exception {
+ // APK signed with v2 scheme only, one signer, one signature.
+ assertInstallSucceedsForEach("v2-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES);
+ assertInstallSucceedsForEach("v2-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES);
+ assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES);
+ assertInstallSucceedsForEach("v2-only-with-rsa-pss-sha256-%s.apk", RSA_KEY_NAMES);
+
+ // DSA with SHA-512 is not supported by Android platform and thus APK Signature Scheme v2
+ // does not support that either
+ // assertInstallSucceedsForEach("v2-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES);
+ assertInstallSucceedsForEach("v2-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES);
+ assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES);
+ assertInstallSucceedsForEach(
+ "v2-only-with-rsa-pss-sha512-%s.apk",
+ RSA_KEY_NAMES_2048_AND_LARGER // 1024-bit key is too short for PSS with SHA-512
+ );
+ }
+
+ public void testInstallV2SignatureDoesNotVerify() throws Exception {
+ // APK signed with v2 scheme only, but the signature over signed-data does not verify.
+ String error = "signature did not verify";
+
+ // Bitflip in certificate field inside signed-data. Based on
+ // v2-only-with-dsa-sha256-1024.apk.
+ assertInstallFailsWithError("v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", error);
+
+ // Signature claims to be RSA PKCS#1 v1.5 with SHA-256, but is actually using SHA-512.
+ // Based on v2-only-with-rsa-pkcs1-sha256-2048.apk.
+ assertInstallFailsWithError(
+ "v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk", error);
+
+ // Signature claims to be RSA PSS with SHA-256 and 32 bytes of salt, but is actually using 0
+ // bytes of salt. Based on v2-only-with-rsa-pkcs1-sha256-2048.apk. Obtained by modifying APK
+ // signer to use the wrong amount of salt.
+ assertInstallFailsWithError(
+ "v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk", error);
+
+ // Bitflip in the ECDSA signature. Based on v2-only-with-ecdsa-sha256-p256.apk.
+ assertInstallFailsWithError(
+ "v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk", error);
+ }
+
+ public void testInstallV2ContentDigestMismatch() throws Exception {
+ // APK signed with v2 scheme only, but the digest of contents does not match the digest
+ // stored in signed-data.
+ String error = "digest of contents did not verify";
+
+ // Based on v2-only-with-rsa-pkcs1-sha512-4096.apk. Obtained by modifying APK signer to
+ // flip the leftmost bit in content digest before signing signed-data.
+ assertInstallFailsWithError(
+ "v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk", error);
+
+ // Based on v2-only-with-ecdsa-sha256-p256.apk. Obtained by modifying APK signer to flip the
+ // leftmost bit in content digest before signing signed-data.
+ assertInstallFailsWithError(
+ "v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk", error);
+ }
+
+ public void testInstallNoApkSignatureSchemeBlock() throws Exception {
+ // APK signed with v2 scheme only, but the rules for verifying APK Signature Scheme v2
+ // signatures say that this APK must not be verified using APK Signature Scheme v2.
+
+ // Obtained from v2-only-with-rsa-pkcs1-sha512-4096.apk by flipping a bit in the magic
+ // field in the footer of APK Signing Block. This makes the APK Signing Block disappear.
+ assertInstallFails("v2-only-wrong-apk-sig-block-magic.apk");
+
+ // Obtained by modifying APK signer to insert "GARBAGE" between ZIP Central Directory and
+ // End of Central Directory. The APK is otherwise fine and is signed with APK Signature
+ // Scheme v2. Based on v2-only-with-rsa-pkcs1-sha256.apk.
+ assertInstallFails("v2-only-garbage-between-cd-and-eocd.apk");
+
+ // Obtained by modifying APK signer to truncate the ZIP Central Directory by one byte. The
+ // APK is otherwise fine and is signed with APK Signature Scheme v2. Based on
+ // v2-only-with-rsa-pkcs1-sha256.apk
+ assertInstallFails("v2-only-truncated-cd.apk");
+
+ // Obtained by modifying the size in APK Signature Block header. Based on
+ // v2-only-with-ecdsa-sha512-p521.apk.
+ assertInstallFails("v2-only-apk-sig-block-size-mismatch.apk");
+
+ // Obtained by modifying the ID under which APK Signature Scheme v2 Block is stored in
+ // APK Signing Block and by modifying the APK signer to not insert anti-stripping
+ // protections into JAR Signature. The APK should appear as having no APK Signature Scheme
+ // v2 Block and should thus successfully verify using JAR Signature Scheme.
+ assertInstallSucceeds("v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk");
+ }
+
+ public void testInstallV2UnknownPairIgnoredInApkSigningBlock() throws Exception {
+ // Obtained by modifying APK signer to emit an unknown ID-value pair into APK Signing Block
+ // before the ID-value pair containing the APK Signature Scheme v2 Block. The unknown
+ // ID-value should be ignored.
+ assertInstallSucceeds("v2-only-unknown-pair-in-apk-sig-block.apk");
+ }
+
+ public void testInstallV2IgnoresUnknownSignatureAlgorithms() throws Exception {
+ // APK is signed with a known signature algorithm and with a couple of unknown ones.
+ // Obtained by modifying APK signer to use "unknown" signature algorithms in addition to
+ // known ones.
+ assertInstallSucceeds("v2-only-with-ignorable-unsupported-sig-algs.apk");
+ }
+
+ public void testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks() throws Exception {
+ // APK is signed with a single signature algorithm, but the digests block claims that it is
+ // signed with two different signature algorithms. Obtained by modifying APK Signer to
+ // emit an additional digest record with signature algorithm 0x12345678.
+ assertInstallFailsWithError(
+ "v2-only-signatures-and-digests-block-mismatch.apk",
+ "Signature algorithms don't match between digests and signatures records");
+ }
+
+ public void testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate() throws Exception {
+ // APK is signed with v2 only. The public key field does not match the public key in the
+ // leaf certificate. Obtained by modifying APK signer to write out a modified leaf
+ // certificate where the RSA modulus has a bitflip.
+ assertInstallFailsWithError(
+ "v2-only-cert-and-public-key-mismatch.apk",
+ "Public key mismatch between certificate and signature record");
+ }
+
+ public void testInstallV2RejectsSignerBlockWithNoCertificates() throws Exception {
+ // APK is signed with v2 only. There are no certificates listed in the signer block.
+ // Obtained by modifying APK signer to output no certificates.
+ assertInstallFailsWithError("v2-only-no-certs-in-sig.apk", "No certificates listed");
+ }
+
+ public void testInstallTwoSigners() throws Exception {
+ // APK signed by two different signers.
+ assertInstallSucceeds("two-signers.apk");
+ // Because the install attempt below is an update, it also tests that the signing
+ // certificates exposed by v2 signatures above are the same as the one exposed by v1
+ // signatures in this APK.
+ assertInstallSucceeds("v1-only-two-signers.apk");
+ assertInstallSucceeds("v2-only-two-signers.apk");
+ }
+
+ public void testInstallV2TwoSignersRejectsWhenOneBroken() throws Exception {
+ // Bitflip in the ECDSA signature of second signer. Based on two-signers.apk.
+ // This asserts that breakage in any signer leads to rejection of the APK.
+ assertInstallFailsWithError(
+ "two-signers-second-signer-v2-broken.apk", "signature did not verify");
+ }
+
+ public void testInstallV2RejectsWhenMissingCode() throws Exception {
+ // Obtained by removing classes.dex from original.apk and then signing with v2 only.
+ // Although this has nothing to do with v2 signature verification, package manager wants
+ // signature verification / certificate collection to reject APKs with missing code
+ // (classes.dex) unless requested otherwise.
+ assertInstallFailsWithError("v2-only-missing-classes.dex.apk", "code is missing");
+ }
+
+ private void assertInstallSucceeds(String apkFilenameInResources) throws Exception {
+ String installResult = installPackageFromResource(apkFilenameInResources);
+ if (installResult != null) {
+ fail("Failed to install " + apkFilenameInResources + ": " + installResult);
+ }
+ }
+
+ private void assertInstallSucceedsForEach(
+ String apkFilenamePatternInResources, String[] args) throws Exception {
+ for (String arg : args) {
+ String apkFilenameInResources =
+ String.format(Locale.US, apkFilenamePatternInResources, arg);
+ String installResult = installPackageFromResource(apkFilenameInResources);
+ if (installResult != null) {
+ fail("Failed to install " + apkFilenameInResources + ": " + installResult);
+ }
+ try {
+ uninstallPackage();
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Failed to uninstall after installing " + apkFilenameInResources, e);
+ }
+ }
+ }
+
+ private void assertInstallFailsWithError(
+ String apkFilenameInResources, String errorSubstring) throws Exception {
+ String installResult = installPackageFromResource(apkFilenameInResources);
+ if (installResult == null) {
+ fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
+ + " with \"" + errorSubstring + "\"");
+ }
+ assertContains(
+ "Install failure message of " + apkFilenameInResources,
+ errorSubstring,
+ installResult);
+ }
+
+ private void assertInstallFails(String apkFilenameInResources) throws Exception {
+ String installResult = installPackageFromResource(apkFilenameInResources);
+ if (installResult == null) {
+ fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail");
+ }
+ }
+
+ private static void assertContains(String message, String expectedSubstring, String actual) {
+ String errorPrefix = ((message != null) && (message.length() > 0)) ? (message + ": ") : "";
+ if (actual == null) {
+ fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was null");
+ }
+ if (!actual.contains(expectedSubstring)) {
+ fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was \""
+ + actual + "\"");
+ }
+ }
+
+ private String installPackageFromResource(String apkFilenameInResources)
+ throws IOException, DeviceNotAvailableException {
+ // ITestDevice.installPackage API requires the APK to be install to be a File. We thus
+ // copy the requested resource into a temporary file, attempt to install it, and delete the
+ // file during cleanup.
+
+ String fullResourceName = TEST_APK_RESOURCE_PREFIX + apkFilenameInResources;
+ File apkFile = File.createTempFile("pkginstalltest", ".apk");
+ try {
+ try (InputStream in = getClass().getResourceAsStream(fullResourceName);
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(apkFile))) {
+ if (in == null) {
+ throw new IllegalArgumentException("Resource not found: " + fullResourceName);
+ }
+ byte[] buf = new byte[65536];
+ int chunkSize;
+ while ((chunkSize = in.read(buf)) != -1) {
+ out.write(buf, 0, chunkSize);
+ }
+ }
+ return mDevice.installPackage(apkFile, true);
+ } finally {
+ apkFile.delete();
+ }
+ }
+
+ private String uninstallPackage() throws DeviceNotAvailableException {
+ return mDevice.uninstallPackage(TEST_PKG);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
index ffa96e8..d362ed6 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
@@ -20,7 +20,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
index b42414c..da3c9e4 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
@@ -16,37 +16,68 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.encryptionapp">
-
<application android:label="EncryptionApp">
<activity android:name=".UnawareActivity"
- android:exported="true"/>
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </activity>
<receiver android:name=".UnawareReceiver"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </receiver>
<service android:name=".UnawareService"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </service>
<provider android:name=".UnawareProvider"
android:authorities="com.android.cts.encryptionapp.unaware"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </provider>
<activity android:name=".AwareActivity"
android:directBootAware="true"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </activity>
<receiver android:name=".AwareReceiver"
android:directBootAware="true"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </receiver>
<service android:name=".AwareService"
android:directBootAware="true"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </service>
<provider android:name=".AwareProvider"
android:authorities="com.android.cts.encryptionapp.aware"
android:directBootAware="true"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.cts.encryptionapp.TEST" />
+ </intent-filter>
+ </provider>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java
index a312a5b..617fa1f 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java
@@ -21,11 +21,16 @@
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
+import android.view.WindowManager;
public class AwareActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(AWARE, "Activity.onCreate()");
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java
index e8807cd..a95fa7d 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java
@@ -25,9 +25,12 @@
import android.util.Log;
public class AwareProvider extends ContentProvider {
+ public static volatile boolean sCreated = false;
+
@Override
public boolean onCreate() {
Log.v(AWARE, "ContentProvider.onCreate()");
+ sCreated = true;
return true;
}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
index 1e161f8..fd7dac7 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
@@ -16,8 +16,369 @@
package com.android.cts.encryptionapp;
-import android.test.AndroidTestCase;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-public class EncryptionAppTest extends AndroidTestCase {
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.SystemClock;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+import android.test.InstrumentationTestCase;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class EncryptionAppTest extends InstrumentationTestCase {
private static final String TAG = "EncryptionAppTest";
+
+ private static final long TIMEOUT = 10 * DateUtils.SECOND_IN_MILLIS;
+
+ private static final String KEY_BOOT = "boot";
+
+ private static final String TEST_PKG = "com.android.cts.encryptionapp";
+ private static final String TEST_ACTION = "com.android.cts.encryptionapp.TEST";
+
+ private static final String OTHER_PKG = "com.android.cts.splitapp";
+
+ private Context mCe;
+ private Context mDe;
+ private PackageManager mPm;
+
+ private UiDevice mDevice;
+ private AwareActivity mActivity;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mCe = getInstrumentation().getContext();
+ mDe = mCe.createDeviceProtectedStorageContext();
+ mPm = mCe.getPackageManager();
+
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ assertNotNull(mDevice);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+
+ if (mActivity != null) {
+ mActivity.finish();
+ }
+ }
+
+ public void testSetUp() throws Exception {
+ // Write both CE/DE data for ourselves
+ assertTrue("CE file", getTestFile(mCe).createNewFile());
+ assertTrue("DE file", getTestFile(mDe).createNewFile());
+
+ doBootCountBefore();
+
+ mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+ AwareActivity.class, null);
+ mDevice.waitForIdle();
+
+ // Set a PIN for this user
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ mActivity.startActivity(intent);
+ mDevice.waitForIdle();
+
+ // Pick PIN from the option list
+ UiObject view = new UiObject(new UiSelector()
+ .resourceId("com.android.settings:id/lock_pin"));
+ assertTrue("lock_pin", view.waitForExists(TIMEOUT));
+ view.click();
+ mDevice.waitForIdle();
+
+ // Ignore any interstitial options
+ view = new UiObject(new UiSelector()
+ .resourceId("com.android.settings:id/encrypt_dont_require_password"));
+ if (view.waitForExists(TIMEOUT)) {
+ view.click();
+ mDevice.waitForIdle();
+ }
+
+ // Set our PIN
+ view = new UiObject(new UiSelector()
+ .resourceId("com.android.settings:id/password_entry"));
+ assertTrue("password_entry", view.waitForExists(TIMEOUT));
+
+ // Enter it twice to confirm
+ enterTestPin();
+ enterTestPin();
+
+ mDevice.pressBack();
+ }
+
+ public void testTearDown() throws Exception {
+ // Just in case, always try tearing down keyguard
+ dismissKeyguard();
+
+ mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+ AwareActivity.class, null);
+ mDevice.waitForIdle();
+
+ // Clear PIN for this user
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ mActivity.startActivity(intent);
+ mDevice.waitForIdle();
+
+ // Enter current PIN
+ UiObject view = new UiObject(new UiSelector()
+ .resourceId("com.android.settings:id/password_entry"));
+ assertTrue("password_entry", view.waitForExists(TIMEOUT));
+
+ enterTestPin();
+
+ // Set back to "none"
+ view = new UiObject(new UiSelector()
+ .resourceId("com.android.settings:id/lock_none"));
+ assertTrue("lock_none", view.waitForExists(TIMEOUT));
+ view.click();
+ mDevice.waitForIdle();
+
+ // Yes, we really want to
+ view = new UiObject(new UiSelector()
+ .resourceId("android:id/button1"));
+ if (view.waitForExists(TIMEOUT)) {
+ view.click();
+ mDevice.waitForIdle();
+ }
+
+ mDevice.pressBack();
+ }
+
+ public void doBootCountBefore() throws Exception {
+ final int thisCount = getBootCount();
+ mDe.getSharedPreferences(KEY_BOOT, 0).edit().putInt(KEY_BOOT, thisCount).commit();
+ }
+
+ public void doBootCountAfter() throws Exception {
+ final int lastCount = mDe.getSharedPreferences(KEY_BOOT, 0).getInt(KEY_BOOT, -1);
+ final int thisCount = getBootCount();
+ assertTrue("Current boot count " + thisCount + " not greater than last " + lastCount,
+ thisCount > lastCount);
+ }
+
+ public void testVerifyUnlockedAndDismiss() throws Exception {
+ doBootCountAfter();
+ assertUnlocked();
+ dismissKeyguard();
+ assertUnlocked();
+ }
+
+ public void testVerifyLockedAndDismiss() throws Exception {
+ doBootCountAfter();
+ assertLocked();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ latch.countDown();
+ }
+ };
+ mDe.registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+
+ dismissKeyguard();
+
+ // Dismiss keyguard should have kicked off immediate broadcast
+ assertTrue("USER_UNLOCKED", latch.await(1, TimeUnit.MINUTES));
+
+ // And we should now be fully unlocked; we run immediately like this to
+ // avoid missing BOOT_COMPLETED due to instrumentation being torn down.
+ assertUnlocked();
+ }
+
+ private void enterTestPin() throws Exception {
+ // TODO: change the combination on my luggage
+ mDevice.waitForIdle();
+ mDevice.pressKeyCode(KeyEvent.KEYCODE_1);
+ mDevice.pressKeyCode(KeyEvent.KEYCODE_2);
+ mDevice.pressKeyCode(KeyEvent.KEYCODE_3);
+ mDevice.pressKeyCode(KeyEvent.KEYCODE_4);
+ mDevice.pressKeyCode(KeyEvent.KEYCODE_5);
+ mDevice.waitForIdle();
+ mDevice.pressEnter();
+ mDevice.waitForIdle();
+ }
+
+ private void dismissKeyguard() throws Exception {
+ mDevice.wakeUp();
+ mDevice.waitForIdle();
+ mDevice.pressMenu();
+ mDevice.waitForIdle();
+ enterTestPin();
+ }
+
+ public void assertLocked() throws Exception {
+ awaitBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+
+ assertFalse("CE exists", getTestFile(mCe).exists());
+ assertTrue("DE exists", getTestFile(mDe).exists());
+
+ assertFalse("isUserUnlocked", mCe.getSystemService(UserManager.class).isUserUnlocked());
+ assertFalse("isUserUnlocked", mDe.getSystemService(UserManager.class).isUserUnlocked());
+
+ assertTrue("AwareProvider", AwareProvider.sCreated);
+ assertFalse("UnawareProvider", UnawareProvider.sCreated);
+
+ assertNotNull("AwareProvider",
+ mPm.resolveContentProvider("com.android.cts.encryptionapp.aware", 0));
+ assertNull("UnawareProvider",
+ mPm.resolveContentProvider("com.android.cts.encryptionapp.unaware", 0));
+
+ assertGetAware(true, 0);
+ assertGetAware(true, MATCH_DIRECT_BOOT_AWARE);
+ assertGetAware(false, MATCH_DIRECT_BOOT_UNAWARE);
+ assertGetAware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+ assertGetUnaware(false, 0);
+ assertGetUnaware(false, MATCH_DIRECT_BOOT_AWARE);
+ assertGetUnaware(true, MATCH_DIRECT_BOOT_UNAWARE);
+ assertGetUnaware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+ assertQuery(1, 0);
+ assertQuery(1, MATCH_DIRECT_BOOT_AWARE);
+ assertQuery(1, MATCH_DIRECT_BOOT_UNAWARE);
+ assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ }
+
+ public void assertUnlocked() throws Exception {
+ awaitBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+ awaitBroadcast(Intent.ACTION_BOOT_COMPLETED);
+
+ assertTrue("CE exists", getTestFile(mCe).exists());
+ assertTrue("DE exists", getTestFile(mDe).exists());
+
+ assertTrue("isUserUnlocked", mCe.getSystemService(UserManager.class).isUserUnlocked());
+ assertTrue("isUserUnlocked", mDe.getSystemService(UserManager.class).isUserUnlocked());
+
+ assertTrue("AwareProvider", AwareProvider.sCreated);
+ assertTrue("UnawareProvider", UnawareProvider.sCreated);
+
+ assertNotNull("AwareProvider",
+ mPm.resolveContentProvider("com.android.cts.encryptionapp.aware", 0));
+ assertNotNull("UnawareProvider",
+ mPm.resolveContentProvider("com.android.cts.encryptionapp.unaware", 0));
+
+ assertGetAware(true, 0);
+ assertGetAware(true, MATCH_DIRECT_BOOT_AWARE);
+ assertGetAware(false, MATCH_DIRECT_BOOT_UNAWARE);
+ assertGetAware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+ assertGetUnaware(true, 0);
+ assertGetUnaware(false, MATCH_DIRECT_BOOT_AWARE);
+ assertGetUnaware(true, MATCH_DIRECT_BOOT_UNAWARE);
+ assertGetUnaware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+ assertQuery(2, 0);
+ assertQuery(1, MATCH_DIRECT_BOOT_AWARE);
+ assertQuery(1, MATCH_DIRECT_BOOT_UNAWARE);
+ assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ }
+
+ private void assertQuery(int count, int flags) throws Exception {
+ final Intent intent = new Intent(TEST_ACTION);
+ assertEquals("activity", count, mPm.queryIntentActivities(intent, flags).size());
+ assertEquals("service", count, mPm.queryIntentServices(intent, flags).size());
+ assertEquals("provider", count, mPm.queryIntentContentProviders(intent, flags).size());
+ assertEquals("receiver", count, mPm.queryBroadcastReceivers(intent, flags).size());
+ }
+
+ private void assertGetUnaware(boolean visible, int flags) throws Exception {
+ assertGet(visible, false, flags);
+ }
+
+ private void assertGetAware(boolean visible, int flags) throws Exception {
+ assertGet(visible, true, flags);
+ }
+
+ private ComponentName buildName(String prefix, String type) {
+ return new ComponentName(TEST_PKG, TEST_PKG + "." + prefix + type);
+ }
+
+ private void assertGet(boolean visible, boolean aware, int flags) throws Exception {
+ final String prefix = aware ? "Aware" : "Unaware";
+
+ ComponentName name;
+ ComponentInfo info;
+
+ name = buildName(prefix, "Activity");
+ try {
+ info = mPm.getActivityInfo(name, flags);
+ assertTrue(name + " visible", visible);
+ assertEquals(name + " directBootAware", aware, info.directBootAware);
+ } catch (NameNotFoundException e) {
+ assertFalse(name + " visible", visible);
+ }
+
+ name = buildName(prefix, "Service");
+ try {
+ info = mPm.getServiceInfo(name, flags);
+ assertTrue(name + " visible", visible);
+ assertEquals(name + " directBootAware", aware, info.directBootAware);
+ } catch (NameNotFoundException e) {
+ assertFalse(name + " visible", visible);
+ }
+
+ name = buildName(prefix, "Provider");
+ try {
+ info = mPm.getProviderInfo(name, flags);
+ assertTrue(name + " visible", visible);
+ assertEquals(name + " directBootAware", aware, info.directBootAware);
+ } catch (NameNotFoundException e) {
+ assertFalse(name + " visible", visible);
+ }
+
+ name = buildName(prefix, "Receiver");
+ try {
+ info = mPm.getReceiverInfo(name, flags);
+ assertTrue(name + " visible", visible);
+ assertEquals(name + " directBootAware", aware, info.directBootAware);
+ } catch (NameNotFoundException e) {
+ assertFalse(name + " visible", visible);
+ }
+ }
+
+ private File getTestFile(Context context) {
+ return new File(context.getFilesDir(), "test");
+ }
+
+ private int getBootCount() throws Exception {
+ return Settings.Global.getInt(mDe.getContentResolver(), Settings.Global.BOOT_COUNT);
+ }
+
+ private void awaitBroadcast(String action) throws Exception {
+ final Context otherContext = mDe.createPackageContext(OTHER_PKG, 0)
+ .createDeviceProtectedStorageContext();
+ final File probe = new File(otherContext.getFilesDir(),
+ getBootCount() + "." + action);
+ for (int i = 0; i < 60; i++) {
+ Log.d(TAG, "Waiting for " + probe + "...");
+ if (probe.exists()) {
+ return;
+ }
+ SystemClock.sleep(1000);
+ }
+ throw new AssertionError("Failed to find " + probe);
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java
index e596741..4978023 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java
@@ -21,11 +21,16 @@
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
+import android.view.WindowManager;
public class UnawareActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(UNAWARE, "Activity.onCreate()");
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java
index 2aae88d..60d57df 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java
@@ -25,9 +25,12 @@
import android.util.Log;
public class UnawareProvider extends ContentProvider {
+ public static volatile boolean sCreated = false;
+
@Override
public boolean onCreate() {
Log.v(UNAWARE, "ContentProvider.onCreate()");
+ sCreated = true;
return true;
}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index d968863..fcf9f38 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -220,6 +220,21 @@
return new File(dir, ".probe_" + System.nanoTime());
}
+ public static File[] buildCommonChildDirs(File dir) {
+ return new File[] {
+ new File(dir, Environment.DIRECTORY_MUSIC),
+ new File(dir, Environment.DIRECTORY_PODCASTS),
+ new File(dir, Environment.DIRECTORY_ALARMS),
+ new File(dir, Environment.DIRECTORY_RINGTONES),
+ new File(dir, Environment.DIRECTORY_NOTIFICATIONS),
+ new File(dir, Environment.DIRECTORY_PICTURES),
+ new File(dir, Environment.DIRECTORY_MOVIES),
+ new File(dir, Environment.DIRECTORY_DOWNLOADS),
+ new File(dir, Environment.DIRECTORY_DCIM),
+ new File(dir, Environment.DIRECTORY_DOCUMENTS),
+ };
+ }
+
public static void assertDirReadOnlyAccess(File path) {
Log.d(TAG, "Asserting read-only access to " + path);
@@ -230,8 +245,9 @@
try {
final File probe = buildProbeFile(path);
- probe.createNewFile();
- probe.delete();
+ assertFalse(probe.createNewFile());
+ assertFalse(probe.exists());
+ assertFalse(probe.delete());
fail("able to create probe!");
} catch (IOException e) {
// expected
@@ -248,8 +264,10 @@
try {
final File probe = buildProbeFile(path);
- probe.createNewFile();
- probe.delete();
+ assertTrue(probe.createNewFile());
+ assertTrue(probe.exists());
+ assertTrue(probe.delete());
+ assertFalse(probe.exists());
} catch (IOException e) {
fail("failed to create probe!");
}
@@ -263,21 +281,29 @@
try {
final File probe = buildProbeFile(path);
- probe.createNewFile();
- probe.delete();
+ assertFalse(probe.createNewFile());
+ assertFalse(probe.exists());
+ assertFalse(probe.delete());
fail("able to create probe!");
} catch (IOException e) {
// expected
}
}
+ public static void assertDirNoWriteAccess(File[] paths) {
+ for (File path : paths) {
+ assertDirNoWriteAccess(path);
+ }
+ }
+
public static void assertDirNoWriteAccess(File path) {
Log.d(TAG, "Asserting no write access to " + path);
try {
final File probe = buildProbeFile(path);
- probe.createNewFile();
- probe.delete();
+ assertFalse(probe.createNewFile());
+ assertFalse(probe.exists());
+ assertFalse(probe.delete());
fail("able to create probe!");
} catch (IOException e) {
// expected
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
index 995da90..14df3cf 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
@@ -19,6 +19,7 @@
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildCommonChildDirs;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
@@ -60,8 +61,13 @@
}
// Keep walking up until we leave device
- while (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
- assertDirReadOnlyAccess(path);
+ while (path != null) {
+ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
+ assertDirReadOnlyAccess(path);
+ } else {
+ assertDirNoWriteAccess(path);
+ }
+ assertDirNoWriteAccess(buildCommonChildDirs(path));
path = path.getParentFile();
}
}
@@ -81,7 +87,9 @@
final File userPath = new File(path, userId);
assertDirNoWriteAccess(path);
+ assertDirNoWriteAccess(buildCommonChildDirs(path));
assertDirNoWriteAccess(userPath);
+ assertDirNoWriteAccess(buildCommonChildDirs(userPath));
}
}
}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
index dba384c..d9dceb8 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
@@ -18,6 +18,7 @@
package="com.android.cts.splitapp">
<uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:label="SplitApp">
<activity android:name=".MyActivity">
@@ -33,6 +34,16 @@
<action android:name="android.intent.action.DATE_CHANGED" />
</intent-filter>
</receiver>
+ <receiver android:name=".LockedBootReceiver" android:exported="true" android:directBootAware="true">
+ <intent-filter>
+ <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".BootReceiver" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseBootReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseBootReceiver.java
new file mode 100644
index 0000000..1106a41
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseBootReceiver.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.io.File;
+
+public class BaseBootReceiver extends BroadcastReceiver {
+ private static final String TAG = "SplitApp";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ context = context.createDeviceProtectedStorageContext();
+ final File probe = new File(context.getFilesDir(),
+ getBootCount(context) + "." + intent.getAction());
+ Log.d(TAG, "Touching probe " + probe);
+ probe.createNewFile();
+ exposeFile(probe);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static int getBootCount(Context context) throws Exception {
+ return Settings.Global.getInt(context.getContentResolver(), Settings.Global.BOOT_COUNT);
+ }
+
+ private static File exposeFile(File file) throws Exception {
+ file.setReadable(true, false);
+ file.setReadable(true, true);
+
+ File dir = file.getParentFile();
+ do {
+ dir.setExecutable(true, false);
+ dir.setExecutable(true, true);
+ dir = dir.getParentFile();
+ } while (dir != null);
+
+ return file;
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BootReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BootReceiver.java
new file mode 100644
index 0000000..150cf1d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BootReceiver.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+public class BootReceiver extends BaseBootReceiver {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/LockedBootReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/LockedBootReceiver.java
new file mode 100644
index 0000000..d00f1de
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/LockedBootReceiver.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+public class LockedBootReceiver extends BaseBootReceiver {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/MyActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/MyActivity.java
new file mode 100644
index 0000000..9b9f01c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/MyActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+import android.app.Activity;
+
+public class MyActivity extends Activity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 0436252..81cf7b3 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -23,6 +23,7 @@
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildCommonChildDirs;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildProbeFile;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.deleteContents;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPathsExceptMedia;
@@ -229,9 +230,14 @@
path = path.getParentFile();
}
- // Keep walking up until we leave device
- while (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
- assertDirReadOnlyAccess(path);
+ // Walk all the way up to root
+ while (path != null) {
+ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
+ assertDirReadOnlyAccess(path);
+ } else {
+ assertDirNoWriteAccess(path);
+ }
+ assertDirNoWriteAccess(buildCommonChildDirs(path));
path = path.getParentFile();
}
}
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
new file mode 100644
index 0000000..15981f6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
@@ -0,0 +1,28 @@
+# 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)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := 23
+LOCAL_PACKAGE_NAME := CtsPkgInstallTinyApp
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest.xml
new file mode 100644
index 0000000..def2931
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.appsecurity.cts.tinyapp"
+ android:versionCode="10"
+ android:versionName="1.0">
+ <application android:label="@string/app_name">
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/tinyapp/res/values/strings.xml
new file mode 100644
index 0000000..70d5a95
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Tiny App for CTS</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/src/android/appsecurity/cts/tinyapp/MainActivity.java b/hostsidetests/appsecurity/test-apps/tinyapp/src/android/appsecurity/cts/tinyapp/MainActivity.java
new file mode 100644
index 0000000..67a7abc
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/src/android/appsecurity/cts/tinyapp/MainActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts.tinyapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ finish();
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
index f7ed4a8..b57a91a 100644
--- a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
+++ b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
@@ -16,6 +16,8 @@
package com.android.cts.contactdirectoryprovider;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
@@ -43,8 +45,8 @@
private static final String CONFIG_NAME = "config";
private static final String SET_CUSTOM_PREFIX = "set_prefix";
private static final String AUTHORITY = "com.android.cts.contact.directory.provider";
- private static final String TEST_ACCOUNT_NAME = "cts@android.com";
- private static final String TEST_ACCOUNT_TYPE = "com.android.cts";
+ // Same as com.android.cts.managedprofile.AccountAuthenticator.ACCOUNT_TYPE
+ private static final String TEST_ACCOUNT_TYPE = "com.android.cts.test";
private static final String DEFAULT_DISPLAY_NAME = "Directory";
private static final String DEFAULT_CONTACT_NAME = "DirectoryContact";
@@ -109,24 +111,30 @@
switch (match) {
case GAL_DIRECTORIES: {
final MatrixCursor cursor = new MatrixCursor(projection);
- final Object[] row = new Object[projection.length];
- for (int i = 0; i < projection.length; i++) {
- final String column = projection[i];
- if (column.equals(Directory.ACCOUNT_NAME)) {
- row[i] = TEST_ACCOUNT_NAME;
- } else if (column.equals(Directory.ACCOUNT_TYPE)) {
- row[i] = TEST_ACCOUNT_TYPE;
- } else if (column.equals(Directory.TYPE_RESOURCE_ID)) {
- row[i] = R.string.directory_resource_id;
- } else if (column.equals(Directory.DISPLAY_NAME)) {
- row[i] = prefix + DEFAULT_DISPLAY_NAME;
- } else if (column.equals(Directory.EXPORT_SUPPORT)) {
- row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY;
- } else if (column.equals(Directory.SHORTCUT_SUPPORT)) {
- row[i] = Directory.SHORTCUT_SUPPORT_NONE;
+ final AccountManager am = getContext().getSystemService(AccountManager.class);
+ Account[] accounts = am.getAccountsByType(TEST_ACCOUNT_TYPE);
+ if (accounts != null) {
+ for (Account account : accounts) {
+ final Object[] row = new Object[projection.length];
+ for (int i = 0; i < projection.length; i++) {
+ final String column = projection[i];
+ if (column.equals(Directory.ACCOUNT_NAME)) {
+ row[i] = account.name;
+ } else if (column.equals(Directory.ACCOUNT_TYPE)) {
+ row[i] = TEST_ACCOUNT_TYPE;
+ } else if (column.equals(Directory.TYPE_RESOURCE_ID)) {
+ row[i] = R.string.directory_resource_id;
+ } else if (column.equals(Directory.DISPLAY_NAME)) {
+ row[i] = prefix + DEFAULT_DISPLAY_NAME;
+ } else if (column.equals(Directory.EXPORT_SUPPORT)) {
+ row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY;
+ } else if (column.equals(Directory.SHORTCUT_SUPPORT)) {
+ row[i] = Directory.SHORTCUT_SUPPORT_NONE;
+ }
+ }
+ cursor.addRow(row);
}
}
- cursor.addRow(row);
return cursor;
}
case GAL_FILTER:
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
index 8f561a6..edeefd3 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
@@ -68,6 +68,9 @@
}
public void testAlwaysOnVpn() throws Exception {
+ // test always-on is null by default
+ assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
+
final CountDownLatch vpnLatch = new CountDownLatch(1);
final ConnectivityManager cm =
@@ -89,6 +92,8 @@
cm.registerNetworkCallback(request, callback);
try {
mDevicePolicyManager.setAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE);
+ assertEquals(VPN_PACKAGE, mDevicePolicyManager.getAlwaysOnVpnPackage(
+ ADMIN_RECEIVER_COMPONENT));
assertTrue("Took too long waiting to establish a VPN-backed connection",
vpnLatch.await(NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS));
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
index f61c796..40e5220 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
@@ -44,7 +44,7 @@
|| temp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
// Compare current temperature and shutdown threshold.
- assertTrue(temp < shutdownTemp
+ assertTrue(temp < shutdownTemp || temp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE
|| shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
// Compare throttling and shutdown thresholds.
assertTrue(throttlingTemp < shutdownTemp
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 1f6bc7c..6d233b7 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -19,6 +19,7 @@
<uses-sdk android:minSdkVersion="20"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
@@ -99,6 +100,13 @@
<data android:mimeType="vnd.android.cursor.item/person" />
</intent-filter>
</activity>
+ <service android:name=".AccountService" android:exported="true">
+ <intent-filter>
+ <action android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator" />
+ </service>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/authenticator.xml b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/authenticator.xml
new file mode 100644
index 0000000..46cbb7e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/authenticator.xml
@@ -0,0 +1,22 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="com.android.cts.test"
+ android:label="@string/label"
+/>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountAuthenticator.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountAuthenticator.java
new file mode 100644
index 0000000..e8cc616
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountAuthenticator.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.managedprofile;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.os.Bundle;
+
+/* package */ class AccountAuthenticator extends AbstractAccountAuthenticator {
+ private static AccountAuthenticator sAuthenticator = null;
+ public static final String ACCOUNT_NAME = "CTS";
+ public static final String ACCOUNT_TYPE = "com.android.cts.test";
+ private static final String AUTH_TOKEN = "authToken";
+ private static final String AUTH_TOKEN_LABEL = "authTokenLabel";
+
+ private AccountAuthenticator(Context context) {
+ super(context);
+ }
+
+ private Bundle createResultBundle() {
+ Bundle result = new Bundle();
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, ACCOUNT_NAME);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+ result.putString(AccountManager.KEY_AUTHTOKEN, AUTH_TOKEN);
+
+ return result;
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws NetworkErrorException {
+ return createResultBundle();
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+ return createResultBundle();
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle options) throws NetworkErrorException {
+ return createResultBundle();
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
+ Bundle options) throws NetworkErrorException {
+
+ Bundle result = new Bundle();
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ return result;
+ }
+
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle options) throws NetworkErrorException {
+ return createResultBundle();
+ }
+
+ @Override
+ public String getAuthTokenLabel(String authTokenType) {
+ return AUTH_TOKEN_LABEL;
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
+ String[] features) throws NetworkErrorException {
+
+ Bundle result = new Bundle();
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ return result;
+ }
+
+ public static synchronized AccountAuthenticator getAuthenticator(Context context) {
+ if (sAuthenticator == null) {
+ sAuthenticator = new AccountAuthenticator(context.getApplicationContext());
+ }
+ return sAuthenticator;
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountService.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountService.java
new file mode 100644
index 0000000..5c34a79
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.managedprofile;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class AccountService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return AccountAuthenticator.getAuthenticator(this).getIBinder();
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
index 0c4e74c..5a2b3fa 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
@@ -16,6 +16,8 @@
package com.android.cts.managedprofile;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.annotation.TargetApi;
import android.app.admin.DevicePolicyManager;
import android.content.ContentProviderOperation;
@@ -50,8 +52,8 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ContactsTest extends AndroidTestCase {
- private static final String TEST_ACCOUNT_NAME = "CTS";
- private static final String TEST_ACCOUNT_TYPE = "com.android.cts.test";
+ private static final String TEST_ACCOUNT_NAME = AccountAuthenticator.ACCOUNT_NAME;
+ private static final String TEST_ACCOUNT_TYPE = AccountAuthenticator.ACCOUNT_TYPE;
// details of a sample primary contact
private static final String PRIMARY_CONTACT_DISPLAY_NAME = "Primary";
private static final String PRIMARY_CONTACT_PHONE = "00000001";
@@ -140,6 +142,11 @@
.getSystemService(Context.DEVICE_POLICY_SERVICE);
}
+ public void testAddTestAccount() {
+ Account account = new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE);
+ AccountManager.get(getContext()).addAccountExplicitly(account, null, null);
+ }
+
public void testPrimaryProfilePhoneAndEmailLookup_insertedAndfound() throws RemoteException,
OperationApplicationException, NotFoundException, IOException {
assertFalse(isManagedProfile());
@@ -1232,6 +1239,9 @@
// Catch all exceptions to let tearDown() run smoothly
e.printStackTrace();
}
+
+ Account account = new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE);
+ AccountManager.get(getContext()).removeAccountExplicitly(account);
}
private InputStream getInputStreamFromUriForTest(String uriString) {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
index c4c02e8..685ad82 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
@@ -44,7 +44,7 @@
private static final String NETWORK_SSID = "com.android.cts.xwde7ktvh8rmjuhr";
// Time duration to allow before assuming that a WiFi operation failed and ceasing to wait.
- private static final long UPDATE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(30);
+ private static final long UPDATE_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(5);
private static final long UPDATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(1);
// Shared WifiManager instance.
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 8eaa606..975cf4b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -751,6 +751,12 @@
}
try {
+ // Add test account
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+ "testAddTestAccount", mParentUserId));
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+ "testAddTestAccount", mProfileUserId));
+
// Install directory provider to both primary and managed profile
installAppAsUser(DIRECTORY_PROVIDER_APK, mProfileUserId);
installAppAsUser(DIRECTORY_PROVIDER_APK, mParentUserId);
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index f33d434..360257a 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -244,19 +244,37 @@
/**
* Asserts the result of a command, wait and re-running it a couple times if necessary.
*/
- protected void assertDelayedShellCommand(String command, String expectedResult)
+ protected void assertDelayedShellCommand(String command, final String expectedResult)
+ throws Exception {
+ assertDelayedShellCommand(command, new ExpectResultChecker() {
+
+ @Override
+ public boolean isExpected(String result) {
+ return expectedResult.equals(result);
+ }
+
+ @Override
+ public String getExpected() {
+ return expectedResult;
+ }
+ });
+ }
+
+ protected void assertDelayedShellCommand(String command, ExpectResultChecker checker)
throws Exception {
final int maxTries = 5;
+ String result = "";
for (int i = 1; i <= maxTries; i++) {
- final String result = executeShellCommand(command).trim();
- if (result.equals(expectedResult))
- return;
+ result = executeShellCommand(command).trim();
+ if (checker.isExpected(result)) return;
Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
- + expectedResult + "' on attempt #" + i + "; sleeping 1s before trying again");
+ + checker.getExpected() + "' on attempt #" + i
+ + "; sleeping 1s before trying again");
Thread.sleep(SECOND_IN_MS);
}
- fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
- + " attempts");
+ fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after "
+ + maxTries
+ + " attempts. Last result: '" + result + "'");
}
protected void setMeteredNetwork() throws Exception {
@@ -265,16 +283,23 @@
if (metered) {
Log.d(TAG, "Active network already metered: " + info);
return;
+ } else {
+ Log.w(TAG, "Active network not metered: " + info);
}
final String netId = setWifiMeteredStatus(true);
assertTrue("Could not set wifi '" + netId + "' as metered ("
+ mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered());
// Set flag so status is reverted on teardown.
mResetMeteredWifi = true;
+ // Sanity check.
+ assertMeteredNetwork(netId, true);
}
- protected String setWifiMeteredStatus(boolean metered) throws Exception {
- mWfm.setWifiEnabled(true);
+ private String setWifiMeteredStatus(boolean metered) throws Exception {
+ // We could call setWifiEnabled() here, but it might take sometime to be in a consistent
+ // state (for example, if one of the saved network is not properly authenticated), so it's
+ // better to let the hostside test take care of that.
+ assertTrue("wi-fi is disabled", mWfm.isWifiEnabled());
// TODO: if it's not guaranteed the device has wi-fi, we need to change the tests
// to make the actual verification of restrictions optional.
final String ssid = mWfm.getConnectionInfo().getSSID();
@@ -286,13 +311,26 @@
final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered;
assertDelayedShellCommand(setCommand, "");
- // Sanity check.
- final String getCommand = "cmd netpolicy get metered-network " + netId;
- assertDelayedShellCommand(getCommand, Boolean.toString(metered));
-
return netId;
}
+ private void assertMeteredNetwork(String netId, boolean status) throws Exception {
+ final String command = "cmd netpolicy list wifi-networks";
+ final String expectedLine = netId + ";" + status;
+ assertDelayedShellCommand(command, new ExpectResultChecker() {
+
+ @Override
+ public boolean isExpected(String result) {
+ return result.contains(expectedLine);
+ }
+
+ @Override
+ public String getExpected() {
+ return "line containing " + expectedLine;
+ }
+ });
+ }
+
protected void setRestrictBackground(boolean enabled) throws Exception {
executeShellCommand("cmd netpolicy set restrict-background " + enabled);
final String output = executeShellCommand("cmd netpolicy get restrict-background ");
@@ -445,4 +483,9 @@
return fullState;
}
}
+
+ protected static interface ExpectResultChecker {
+ boolean isExpected(String result);
+ String getExpected();
+ }
}
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
index 08fb887..ab1b7d6 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -63,6 +63,8 @@
assertNotNull(mAbi);
assertNotNull(mCtsBuild);
+ assertTrue("device not connected to network", getDevice().checkConnectivity());
+
uninstallPackage(TEST_PKG, false);
installPackage(TEST_APK);
}
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
index b75ea94..808899a 100644
--- a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
@@ -132,13 +132,16 @@
// Compute the stats.
Stat.StatResult stat = Stat.getStat(result);
// Get the report for this test and add the results to record.
+ String reportLogName = "SampleHostTestMetrics";
+ String streamName = "test_transfer_time_metrics";
MetricsReportLog report = new MetricsReportLog(mDevice.getSerialNumber(), mAbi.getName(),
- String.format("%s#testTransferTime", getClass().getCanonicalName()));
- report.addValues("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
- report.addValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
- report.addValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
+ String.format("%s#testTransferTime", getClass().getCanonicalName()),
+ reportLogName, streamName);
+ report.addValues("times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+ report.addValue("min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
+ report.addValue("max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
// Every report must have a summary,
- report.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+ report.setSummary("average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
// Send the report to Tradefed.
report.submit();
}
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index 1b32669..34e0e8a 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -30,6 +30,8 @@
LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
LOCAL_CTS_TEST_PACKAGE := android.host.security
selinux_general_seapp_contexts := $(call intermediates-dir-for,ETC,general_seapp_contexts)/general_seapp_contexts
@@ -57,7 +59,14 @@
selinux_neverallow_gen_data := cts/tools/selinux/SELinuxNeverallowTestFrame.py
-LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze
+old_cts_sepolicy-analyze := $(CTS_TESTCASES_OUT)/sepolicy-analyze
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze \
+ $(old_cts_sepolicy-analyze)
+
+$(old_cts_sepolicy-analyze) : $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
+ mkdir -p $(dir $@)
+ $(copy-file-to-target)
LOCAL_GENERATED_SOURCES := $(call local-generated-sources-dir)/android/cts/security/SELinuxNeverallowRulesTest.java
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 222533a..0a26c97 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -16,7 +16,7 @@
package android.security.cts;
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -66,19 +66,19 @@
private File deviceSvcFile;
private File seappNeverAllowFile;
+ private IBuildInfo mBuild;
+
/**
* A reference to the device under test.
*/
private ITestDevice mDevice;
- private CompatibilityBuildHelper mHelper;
-
/**
* {@inheritDoc}
*/
@Override
public void setBuild(IBuildInfo build) {
- mHelper = new CompatibilityBuildHelper(build);
+ mBuild = build;
}
/**
@@ -107,7 +107,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- sepolicyAnalyze = new File(mHelper.getTestsDir(), "sepolicy-analyze");
+ sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
sepolicyAnalyze.setExecutable(true);
/* obtain sepolicy file from running device */
diff --git a/libs/runner/Android.mk b/libs/runner/Android.mk
index 9642f53..15f64a3 100644
--- a/libs/runner/Android.mk
+++ b/libs/runner/Android.mk
@@ -16,9 +16,7 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, ../../tests/core/runner/src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
LOCAL_MODULE_TAGS := optional
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index bb199b4..1256546 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -205,7 +205,8 @@
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
synchronized (waitObject) {
- if (!mAccessibilityManager.isEnabled() && (System.currentTimeMillis() < timeoutTime)) {
+ while (!mAccessibilityManager.isEnabled()
+ && (System.currentTimeMillis() < timeoutTime)) {
waitObject.wait(timeoutTime - System.currentTimeMillis());
}
}
@@ -227,7 +228,8 @@
mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
synchronized (waitObject) {
- if (!mAccessibilityManager.isEnabled() && (System.currentTimeMillis() < timeoutTime)) {
+ while (!mAccessibilityManager.isTouchExplorationEnabled()
+ && (System.currentTimeMillis() < timeoutTime)) {
waitObject.wait(timeoutTime - System.currentTimeMillis());
}
}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
index 293feec..ffbe833 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
@@ -20,6 +20,7 @@
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
import android.view.accessibility.AccessibilityWindowInfo;
/**
@@ -34,7 +35,7 @@
AccessibilityWindowInfo w2 = AccessibilityWindowInfo.obtain(w1);
assertNotSame(w1, w2);
- assertEquals(w1, w2);
+ assertTrue(areWindowsEqual(w1, w2));
}
@SmallTest
@@ -45,8 +46,7 @@
parcel.setDataPosition(0);
AccessibilityWindowInfo w2 = AccessibilityWindowInfo.CREATOR.createFromParcel(parcel);
assertNotSame(w1, w2);
- assertEquals(w1, w2);
-
+ assertTrue(areWindowsEqual(w1, w2));
}
@SmallTest
@@ -62,6 +62,7 @@
assertFalse(w.isAccessibilityFocused());
assertFalse(w.isActive());
assertFalse(w.isFocused());
+ assertNull(w.getTitle());
Rect rect = new Rect();
w.getBoundsInScreen(rect);
@@ -87,4 +88,19 @@
// Expected.
}
}
+
+ private boolean areWindowsEqual(AccessibilityWindowInfo w1, AccessibilityWindowInfo w2) {
+ boolean equality = w1.equals(w2);
+ equality &= TextUtils.equals(w1.getTitle(), w2.getTitle());
+ equality &= w1.isAccessibilityFocused() == w2.isAccessibilityFocused();
+ equality &= w1.isActive() == w2.isActive();
+ equality &= w1.getType() == w2.getType();
+ equality &= w1.getLayer() == w2.getLayer();
+ Rect bounds1 = new Rect();
+ Rect bounds2 = new Rect();
+ w1.getBoundsInScreen(bounds1);
+ w2.getBoundsInScreen(bounds2);
+ equality &= bounds1.equals(bounds2);
+ return equality;
+ }
}
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 1dfb5e0..227602f 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <application android:theme="@android:style/Theme.Material.NoActionBar">
+ <application android:theme="@android:style/Theme.Holo.NoActionBar">
<uses-library android:name="android.test.runner" />
@@ -45,6 +45,9 @@
android:label="@string/accessibility_text_traversal_test_activity"
android:name=".AccessibilityTextTraversalActivity"/>
+ <activity android:label="Activity for testing window accessibility reporting"
+ android:name=".AccessibilityWindowReportingActivity"/>
+
<activity
android:label="Full screen activity for gesture dispatch testing"
android:name=".AccessibilityGestureDispatchTest$GestureDispatchActivity" />
diff --git a/tests/accessibilityservice/res/layout/accessibility_window_reporting_test.xml b/tests/accessibilityservice/res/layout/accessibility_window_reporting_test.xml
new file mode 100644
index 0000000..074343e
--- /dev/null
+++ b/tests/accessibilityservice/res/layout/accessibility_window_reporting_test.xml
@@ -0,0 +1,10 @@
+<?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">
+ <AutoCompleteTextView
+ android:id="@+id/autoCompleteLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
index 4eb625c..c970f48 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
@@ -86,31 +86,21 @@
getActivity();
mContext = getInstrumentation().getContext();
- UiAutomation uiAutomation;
- try {
- uiAutomation = getUiAutomation();
- } catch (RuntimeException e) {
- // Clean up UI Automation after other tests as we cannot request UI Automation with
- // different flags if one already exists.
- uiAutomation = getInstrumentation().getUiAutomation();
- uiAutomation.destroy();
-
- // Try to get UI Automation again.
- uiAutomation = getUiAutomation();
- }
String command = "pm grant " + mContext.getPackageName()
+ "android.permission.WRITE_SECURE_SETTINGS";
- executeShellCommand(uiAutomation, command);
- uiAutomation.destroy();
+ executeShellCommand(getUiAutomation(), command);
- disableAllServices();
+ if (mService != null) {
+ mService.disableSelf();
+ }
enableTestService();
-
}
@Override
public void tearDown() throws Exception {
- disableAllServices();
+ if (mService != null) {
+ mService.disableSelf();
+ }
}
public void testApiReturnValues_shouldChangeValueOnRequestAndSendCallback() throws Exception {
@@ -174,8 +164,7 @@
assertEquals(numWindowsWithIme, mService.getTestWindowsListSize());
}
-
- public void testHideSoftKeyboard_shouldHideKeyboardUntilAllServicesDisabled() throws Exception {
+ public void testHideSoftKeyboard_shouldHideKeyboardUntilServiceIsDisabled() throws Exception {
// The soft keyboard should be in its' default mode.
assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
@@ -192,7 +181,7 @@
assertEquals(numWindowsWithIme - 1, mService.getTestWindowsListSize());
// Make sure we can see the soft keyboard once all Accessibility Services are disabled.
- disableAllServices();
+ mService.disableSelf();
waitForWindowStateChanged();
waitForIdle();
@@ -245,9 +234,8 @@
}
private void waitForWindowStateChanged() throws Exception {
- UiAutomation uiAutomation = getUiAutomation();
try {
- uiAutomation.executeAndWaitForEvent(new Runnable() {
+ getUiAutomation().executeAndWaitForEvent(new Runnable() {
@Override
public void run() {
// Do nothing.
@@ -263,46 +251,9 @@
} catch (TimeoutException ignored) {
// Ignore since the event could have occured before this method was called. There should
// be a check after this method returns to catch incorrect values.
- } finally {
- uiAutomation.destroy();
}
}
- private void disableAllServices() throws Exception {
- final Object waitLockForA11yOff = new Object();
- AccessibilityManager manager =
- (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
- manager.addAccessibilityStateChangeListener(
- new AccessibilityManager.AccessibilityStateChangeListener() {
- @Override
- public void onAccessibilityStateChanged(boolean b) {
- synchronized (waitLockForA11yOff) {
- waitLockForA11yOff.notifyAll();
- }
- }
- });
- ContentResolver cr = mContext.getContentResolver();
- UiAutomation uiAutomation = getUiAutomation();
- executeShellCommand(uiAutomation, "settings put secure "
- + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " null");
- uiAutomation.destroy();
- StubSoftKeyboardModesAccessibilityService.sInstance = null;
- long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_SERVICE_TOGGLE_MS;
- while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
- synchronized (waitLockForA11yOff) {
- if (!manager.isEnabled()) {
- return;
- }
- try {
- waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
- } catch (InterruptedException e) {
- // Ignored; loop again
- }
- }
- }
- throw new RuntimeException("Unable to turn accessibility off");
- }
-
private void enableTestService() throws Exception {
Context context = getInstrumentation().getContext();
AccessibilityManager manager =
@@ -321,7 +272,6 @@
executeShellCommand(uiAutomation, command);
executeShellCommand(uiAutomation, "settings put secure "
+ Settings.Secure.ACCESSIBILITY_ENABLED + " 1");
- uiAutomation.destroy();
// We have enabled the services of interest and need to wait until they
// are instantiated and started (if needed) and the system binds to them.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
new file mode 100644
index 0000000..e94cb11
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.app.UiAutomation;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Test cases for actions taken on text views.
+ */
+public class AccessibilityTextActionTest extends
+ AccessibilityActivityTestCase<AccessibilityTextTraversalActivity> {
+ UiAutomation mUiAutomation;
+
+ public AccessibilityTextActionTest() {
+ super(AccessibilityTextTraversalActivity.class);
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+ mUiAutomation = getInstrumentation().getUiAutomation();
+ }
+
+ public void tearDown() throws Exception {
+ mUiAutomation.destroy();
+ super.tearDown();
+ }
+
+ public void testNotEditableTextView_shouldNotExposeOrRespondToSetTextAction() {
+ final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(getString(R.string.a_b));
+ }
+ });
+
+ final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
+ .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+
+ assertFalse("Standard text view should not support SET_TEXT", text.getActionList()
+ .contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+ assertEquals("Standard text view should not support SET_TEXT", 0,
+ text.getActions() & AccessibilityNodeInfo.ACTION_SET_TEXT);
+ Bundle args = new Bundle();
+ args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
+ getString(R.string.text_input_blah));
+ assertFalse(text.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args));
+
+ getInstrumentation().waitForIdleSync();
+ assertTrue("Text view should not update on failed set text",
+ TextUtils.equals(getString(R.string.a_b), textView.getText()));
+ }
+
+ public void testEditableTextView_shouldExposeAndRespondToSetTextAction() {
+ final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(getString(R.string.a_b), TextView.BufferType.EDITABLE);
+ }
+ });
+
+ final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
+ .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+
+ assertTrue("Editable text view should support SET_TEXT", text.getActionList()
+ .contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+ assertEquals("Editable text view should support SET_TEXT",
+ AccessibilityNodeInfo.ACTION_SET_TEXT,
+ text.getActions() & AccessibilityNodeInfo.ACTION_SET_TEXT);
+
+ Bundle args = new Bundle();
+ String textToSet = getString(R.string.text_input_blah);
+ args.putCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, textToSet);
+
+ assertTrue(text.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args));
+
+ getInstrumentation().waitForIdleSync();
+ assertTrue("Editable text should update on set text",
+ TextUtils.equals(textToSet, textView.getText()));
+ }
+
+ public void testEditText_shouldExposeAndRespondToSetTextAction() {
+ final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ editText.setVisibility(View.VISIBLE);
+ editText.setText(getString(R.string.a_b));
+ }
+ });
+
+ final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
+ .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+
+ assertTrue("EditText should support SET_TEXT", text.getActionList()
+ .contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+ assertEquals("EditText view should support SET_TEXT",
+ AccessibilityNodeInfo.ACTION_SET_TEXT,
+ text.getActions() & AccessibilityNodeInfo.ACTION_SET_TEXT);
+
+ Bundle args = new Bundle();
+ String textToSet = getString(R.string.text_input_blah);
+ args.putCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, textToSet);
+
+ assertTrue(text.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args));
+
+ getInstrumentation().waitForIdleSync();
+ assertTrue("EditText should update on set text",
+ TextUtils.equals(textToSet, editText.getText()));
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
new file mode 100644
index 0000000..d17a285
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.os.Bundle;
+
+/**
+ * Activity used by ActivityWindowReportingTest
+ */
+public class AccessibilityWindowReportingActivity extends AccessibilityTestActivity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.accessibility_window_reporting_test);
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
new file mode 100644
index 0000000..dec3131
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.UiAutomation;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Tests that AccessibilityWindowInfos are properly populated
+ */
+public class AccessibilityWindowReportingTest
+ extends AccessibilityActivityTestCase<AccessibilityWindowReportingActivity> {
+ UiAutomation mUiAutomation;
+
+ public AccessibilityWindowReportingTest() {
+ super(AccessibilityWindowReportingActivity.class);
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+ mUiAutomation = getInstrumentation().getUiAutomation();
+ AccessibilityServiceInfo info = mUiAutomation.getServiceInfo();
+ info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+ mUiAutomation.setServiceInfo(info);
+ }
+
+ public void tearDown() throws Exception {
+ mUiAutomation.destroy();
+ super.tearDown();
+ }
+
+ public void testWindowTitle_getTitleReturnsTitle() {
+ final String title = "Some title";
+ setTitleSync(title);
+ AccessibilityWindowInfo window = findWindowByTitle(title);
+ assertNotNull("Window title not reported to accessibility", window);
+ window.recycle();
+ }
+
+ public void testGetAnchorForDropDownForAutoCompleteTextView_returnsTextViewNode() {
+ final AutoCompleteTextView autoCompleteTextView =
+ (AutoCompleteTextView) getActivity().findViewById(R.id.autoCompleteLayout);
+ AccessibilityNodeInfo autoCompleteTextInfo = mUiAutomation.getRootInActiveWindow()
+ .findAccessibilityNodeInfosByViewId(
+ "android.accessibilityservice.cts:id/autoCompleteLayout")
+ .get(0);
+
+ // For the drop-down
+ final String[] COUNTRIES = new String[] {"Belgium", "France", "Italy", "Germany", "Spain"};
+
+ try {
+ mUiAutomation.executeAndWaitForEvent(new Runnable() {
+ @Override
+ public void run() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+ autoCompleteTextView.setAdapter(adapter);
+ autoCompleteTextView.showDropDown();
+ }
+ });
+ }
+ }, new UiAutomation.AccessibilityEventFilter() {
+ @Override
+ public boolean accept(AccessibilityEvent event) {
+ return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+ }
+ }, TIMEOUT_ASYNC_PROCESSING);
+ } catch (TimeoutException exception) {
+ throw new RuntimeException(
+ "Failed to get window changed event when showing dropdown", exception);
+ }
+
+ // Find the pop-up window
+ boolean foundPopup = false;
+ List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
+ for (int i = 0; i < windows.size(); i++) {
+ AccessibilityWindowInfo window = windows.get(i);
+ if (window.getAnchor() == null) {
+ continue;
+ }
+ assertEquals(autoCompleteTextInfo, window.getAnchor());
+ assertFalse("Found multiple pop-ups anchored to one text view", foundPopup);
+ foundPopup = true;
+ }
+ assertTrue("Failed to find accessibility window for auto-complete pop-up", foundPopup);
+ }
+
+ private AccessibilityWindowInfo findWindowByTitle(CharSequence title) {
+ List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
+ AccessibilityWindowInfo returnValue = null;
+ for (int i = 0; i < windows.size(); i++) {
+ AccessibilityWindowInfo window = windows.get(i);
+ if (TextUtils.equals(title, window.getTitle())) {
+ returnValue = window;
+ } else {
+ window.recycle();
+ }
+ }
+ return returnValue;
+ }
+
+ private void setTitleSync(final String title) {
+ try {
+ waitForIdle();
+ mUiAutomation.executeAndWaitForEvent(new Runnable() {
+ @Override
+ public void run() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().getWindow().setTitle(title);
+ }
+ });
+ // TODO: Setting the title should trigger an update of windows
+ mUiAutomation.performGlobalAction(
+ AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+ mUiAutomation.performGlobalAction(
+ AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+ }
+ }, new UiAutomation.AccessibilityEventFilter() {
+ @Override
+ public boolean accept(AccessibilityEvent event) {
+ return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+ }
+ }, TIMEOUT_ASYNC_PROCESSING);
+ } catch (TimeoutException exception) {
+ throw new RuntimeException(
+ "Failed to get window changed event on title change", exception);
+ }
+ }
+}
diff --git a/tests/core/libcore/tests/Android.mk b/tests/core/libcore/tests/Android.mk
index 82ab12e..6429558 100644
--- a/tests/core/libcore/tests/Android.mk
+++ b/tests/core/libcore/tests/Android.mk
@@ -16,6 +16,6 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.tests
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests mockito-target-minus-junit4
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/runner/Android.mk b/tests/core/runner/Android.mk
index 158a1f1..1355512 100644
--- a/tests/core/runner/Android.mk
+++ b/tests/core/runner/Android.mk
@@ -23,12 +23,44 @@
# include this package in the tests target for continuous testing
LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
LOCAL_PACKAGE_NAME := android.core.tests.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
include $(BUILD_CTSCORE_PACKAGE)
+
+#==========================================================
+# Build the core runner.
+#==========================================================
+
+# Build library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_MODULE := cts-core-test-runner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ compatibility-device-util \
+ android-support-test \
+ android.test.runner \
+ vogarexpect
+
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
+include $(BUILD_JAVA_LIBRARY)
+
+#==========================================================
+# Build the run listener
+#==========================================================
+
+# Build library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under,src/com/android/cts/runner)
+LOCAL_MODULE := cts-test-runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
similarity index 95%
rename from tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java
rename to tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
index 24d8819..c6c8504 100644
--- a/tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.support.test.runner.AndroidJUnitRunner;
/**
* Constants used to communicate to and from {@link AndroidJUnitRunner}.
*/
-interface AndroidJUnitRunnerConstants {
+public interface AndroidJUnitRunnerConstants {
/**
* The names of the file containing the names of the tests to run.
@@ -82,5 +82,5 @@
/**
* An identifier for tests run using this class.
*/
- String REPORT_VALUE_ID = "IcuTestRunner";
+ String REPORT_VALUE_ID = "CoreTestRunner";
}
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
similarity index 72%
rename from tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
rename to tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
index 51c4999..144e9e2 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.app.Activity;
import android.app.Instrumentation;
-import android.icu.junit.IcuTestRunnerBuilder;
+import com.android.cts.core.runner.support.ExtendedAndroidRunnerBuilder;
import android.os.Bundle;
import android.os.Debug;
import android.support.test.internal.util.AndroidRunnerParams;
import android.util.Log;
+import com.google.common.base.Splitter;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -45,22 +45,26 @@
import vogar.ExpectationStore;
import vogar.ModeId;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
/**
* A drop-in replacement for AndroidJUnitTestRunner, which understands the same arguments, and has
- * similar functionality, but runs ICU tests instead of calling the JUnit wrapper.
+ * similar functionality, but can filter by expectations and allows a custom runner-builder to be
+ * provided.
*/
-public final class IcuTestRunner extends Instrumentation {
+public class CoreTestRunner extends Instrumentation {
- public static final String TAG = "IcuTestRunner";
+ public static final String TAG = "LibcoreTestRunner";
- private static final List<String> EXPECTATIONS_PATHS =
- Collections.singletonList("expectations/icu-known-failures.txt");
+ private static final java.lang.String ARGUMENT_ROOT_CLASSES = "core-root-classes";
+
+ private static final String ARGUMENT_EXPECTATIONS = "core-expectations";
+
+ private static final Splitter CLASS_LIST_SPLITTER = Splitter.on(',').trimResults();
/** The args for the runner. */
private Bundle args;
@@ -80,10 +84,10 @@
/**
* The list of tests to run.
*/
- private IcuTestList icuTestList;
+ private TestList testList;
@Override
- public void onCreate(Bundle args) {
+ public void onCreate(final Bundle args) {
super.onCreate(args);
this.args = args;
@@ -102,7 +106,9 @@
this.testCountOnly = args.getBoolean(ARGUMENT_COUNT);
try {
- Set<String> expectationResources = new LinkedHashSet<>(EXPECTATIONS_PATHS);
+ // Get the set of resource names containing the expectations.
+ Set<String> expectationResources = new LinkedHashSet<>(
+ CLASS_LIST_SPLITTER.splitToList(args.getString(ARGUMENT_EXPECTATIONS)));
expectationStore = ExpectationStore.parseResources(
getClass(), expectationResources, ModeId.DEVICE);
} catch (IOException e) {
@@ -131,11 +137,16 @@
}
if (testNameList == null) {
- icuTestList = IcuTestList.rootList(Arrays.asList(
- "android.icu.cts.coverage.TestAll",
- "android.icu.dev.test.TestAll"));
+ String rootClasses = args.getString(ARGUMENT_ROOT_CLASSES);
+ if (rootClasses == null) {
+ throw new IllegalStateException(
+ "No tests specified, neither exclusive list or root class");
+ } else {
+ List<String> roots = CLASS_LIST_SPLITTER.splitToList(rootClasses);
+ testList = TestList.rootList(roots);
+ }
} else {
- icuTestList = IcuTestList.exclusiveList(testNameList);
+ testList = TestList.exclusiveList(testNameList);
}
start();
@@ -157,15 +168,15 @@
Request request;
int totalTestCount;
try {
- RunnerBuilder runnerBuilder = new IcuTestRunnerBuilder(runnerParams);
- Class[] classes = icuTestList.getClassesToRun();
+ RunnerBuilder runnerBuilder = new ExtendedAndroidRunnerBuilder(runnerParams);
+ Class[] classes = testList.getClassesToRun();
Runner suite = new Computer().getSuite(runnerBuilder, classes);
if (suite instanceof Filterable) {
Filterable filterable = (Filterable) suite;
// Filter out all the tests that are expected to fail.
- Filter filter = new IcuTestFilter(icuTestList, expectationStore);
+ Filter filter = new TestFilter(testList, expectationStore);
try {
filterable.filter(filter);
@@ -183,17 +194,18 @@
throw new RuntimeException("Could not create a suite", e);
}
- IcuRunListener icuRunListener = new IcuRunListener(this, runnerParams, totalTestCount);
- core.addListener(icuRunListener);
+ StatusUpdaterRunListener statusUpdaterRunListener =
+ new StatusUpdaterRunListener(this, runnerParams, totalTestCount);
+ core.addListener(statusUpdaterRunListener);
core.run(request);
Bundle results;
if (testCountOnly) {
- results = icuRunListener.getCountResults();
+ results = statusUpdaterRunListener.getCountResults();
Log.d(TAG, "test count only: " + results);
} else {
// Get the final results to send back.
- results = icuRunListener.getFinalResults();
+ results = statusUpdaterRunListener.getFinalResults();
}
Log.d(TAG, "Finished");
diff --git a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java b/tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
similarity index 92%
rename from tests/tests/icu/src/android/icu/cts/IcuRunListener.java
rename to tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
index 0a6f355..429ae92 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.app.Instrumentation;
import android.os.Bundle;
@@ -30,8 +30,8 @@
import static android.app.Instrumentation.REPORT_KEY_IDENTIFIER;
import static android.app.Instrumentation.REPORT_KEY_STREAMRESULT;
-import static android.icu.cts.AndroidJUnitRunnerConstants.REPORT_KEY_RUNTIME;
-import static android.icu.cts.AndroidJUnitRunnerConstants.REPORT_VALUE_ID;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.REPORT_KEY_RUNTIME;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.REPORT_VALUE_ID;
import static android.test.InstrumentationTestRunner.REPORT_KEY_NAME_CLASS;
import static android.test.InstrumentationTestRunner.REPORT_KEY_NAME_TEST;
import static android.test.InstrumentationTestRunner.REPORT_KEY_NUM_CURRENT;
@@ -47,7 +47,7 @@
* Listens to result of running tests, collates details and sends intermediate status information
* back to the host.
*/
-class IcuRunListener extends RunListener {
+class StatusUpdaterRunListener extends RunListener {
/**
* The {@link Instrumentation} for which this will report information.
@@ -77,7 +77,8 @@
private long testStartTime;
- public IcuRunListener(Instrumentation instrumentation, AndroidRunnerParams runnerParams,
+ public StatusUpdaterRunListener(Instrumentation instrumentation,
+ AndroidRunnerParams runnerParams,
int totalTestCount) {
this.instrumentation = instrumentation;
this.runnerParams = runnerParams;
@@ -135,6 +136,7 @@
} else {
resultStatus = REPORT_VALUE_RESULT_ERROR;
}
+
String information = failure.getTrace();
currentTestResult.putString(REPORT_KEY_STACK, information);
String output = "Error: " + description + "\n" + information;
@@ -165,7 +167,7 @@
public Bundle getFinalResults() {
int totalTests = totalFailures + totalSuccess;
- Log.d(IcuTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
+ Log.d(CoreTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
+ totalTests + " tests, " + totalSuccess + " passed, " + totalFailures + " failed");
Bundle results = new Bundle();
results.putString(REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -189,7 +191,7 @@
}
public Bundle getCountResults() {
- Log.d(IcuTestRunner.TAG, "Counted " + (totalFailures + totalSuccess) + " tests, "
+ Log.d(CoreTestRunner.TAG, "Counted " + (totalFailures + totalSuccess) + " tests, "
+ totalSuccess + " passed, " + totalFailures + " failed");
Bundle results = new Bundle();
results.putString(REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java b/tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
similarity index 90%
rename from tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
rename to tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
index 3da2976..8cadbcf 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.util.Log;
import java.util.List;
@@ -61,15 +61,15 @@
* {@link ParentRunner}, as that would prevent it from traversing the hierarchy and finding
* the leaf nodes.
*/
-class IcuTestFilter extends Filter {
+class TestFilter extends Filter {
private final ExpectationStore expectationStore;
- private final IcuTestList icuTestList;
+ private final TestList testList;
- public IcuTestFilter(IcuTestList icuTestList, @Nullable ExpectationStore expectationStore) {
+ public TestFilter(TestList testList, @Nullable ExpectationStore expectationStore) {
this.expectationStore = expectationStore;
- this.icuTestList = icuTestList;
+ this.testList = testList;
}
@Override
@@ -84,14 +84,14 @@
String testName = className + "#" + methodName;
// If the test isn't in the list of tests to run then do not run it.
- if (!icuTestList.shouldRunTest(testName)) {
+ if (!testList.shouldRunTest(testName)) {
return false;
}
if (expectationStore != null) {
Expectation expectation = expectationStore.get(testName);
if (expectation.getResult() != Result.SUCCESS) {
- Log.d(IcuTestRunner.TAG, "Excluding test " + description
+ Log.d(CoreTestRunner.TAG, "Excluding test " + testDescription
+ " as it matches expectation: " + expectation);
return false;
}
@@ -126,6 +126,6 @@
@Override
public String describe() {
- return "IcuTestFilter";
+ return "TestFilter";
}
}
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestList.java b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
similarity index 84%
rename from tests/tests/icu/src/android/icu/cts/IcuTestList.java
rename to tests/core/runner/src/com/android/cts/core/runner/TestList.java
index a9c3c5f..4b0452d 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestList.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.util.Log;
import java.util.ArrayList;
@@ -25,7 +25,7 @@
/**
* A list of the tests to run.
*/
-class IcuTestList {
+class TestList {
/**
* The names of the set of tests to run, if null then all tests should be run.
@@ -35,7 +35,7 @@
private final List<Class<?>> classesToRun;
- public static IcuTestList exclusiveList(List<String> testNameList) {
+ public static TestList exclusiveList(List<String> testNameList) {
Set<String> classNamesToRun = new LinkedHashSet<>();
Set<String> testsToRun = new LinkedHashSet<>(testNameList);
@@ -50,19 +50,19 @@
classNamesToRun.add(className);
}
- Log.d(IcuTestRunner.TAG, "Running only the following tests: " + testsToRun);
- return new IcuTestList(getClasses(classNamesToRun), testsToRun);
+ Log.d(CoreTestRunner.TAG, "Running only the following tests: " + testsToRun);
+ return new TestList(getClasses(classNamesToRun), testsToRun);
}
- public static IcuTestList rootList(List<String> rootList) {
+ public static TestList rootList(List<String> rootList) {
// Run from the root test class.
Set<String> classNamesToRun = new LinkedHashSet<>(rootList);
- Log.d(IcuTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
+ Log.d(CoreTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
List<Class<?>> classesToRun1 = getClasses(classNamesToRun);
- return new IcuTestList(classesToRun1, null);
+ return new TestList(classesToRun1, null);
}
private static List<Class<?>> getClasses(Set<String> classNames) {
@@ -83,7 +83,7 @@
* @param testsToRun The exclusive set of tests to run or null if all tests reachable from the
* classes are to be run.
*/
- private IcuTestList(List<Class<?>> classes, Set<String> testsToRun) {
+ private TestList(List<Class<?>> classes, Set<String> testsToRun) {
this.testsToRun = testsToRun;
this.classesToRun = classes;
}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
new file mode 100644
index 0000000..bdb3e57
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit3.AndroidJUnit3Builder;
+import android.support.test.internal.runner.junit3.AndroidSuiteBuilder;
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.runner.junit4.AndroidJUnit4Builder;
+import android.support.test.internal.util.AndroidRunnerParams;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.internal.builders.AnnotatedBuilder;
+import org.junit.internal.builders.IgnoredBuilder;
+import org.junit.internal.builders.JUnit3Builder;
+import org.junit.internal.builders.JUnit4Builder;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * A {@link RunnerBuilder} that can handle all types of tests.
+ */
+// A copy of package private class android.support.test.internal.runner.AndroidRunnerBuilder.
+// Copied here so that it can be extended.
+class AndroidRunnerBuilder extends AllDefaultPossibilitiesBuilder {
+
+ private final AndroidJUnit3Builder mAndroidJUnit3Builder;
+ private final AndroidJUnit4Builder mAndroidJUnit4Builder;
+ private final AndroidSuiteBuilder mAndroidSuiteBuilder;
+ private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
+ // TODO: customize for Android ?
+ private final IgnoredBuilder mIgnoredBuilder;
+
+ /**
+ * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
+ */
+ AndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
+ super(true);
+ mAndroidJUnit3Builder = new AndroidJUnit3Builder(runnerParams);
+ mAndroidJUnit4Builder = new AndroidJUnit4Builder(runnerParams);
+ mAndroidSuiteBuilder = new AndroidSuiteBuilder(runnerParams);
+ mAndroidAnnotatedBuilder = new AndroidAnnotatedBuilder(this, runnerParams);
+ mIgnoredBuilder = new IgnoredBuilder();
+ }
+
+ @Override
+ protected JUnit4Builder junit4Builder() {
+ return mAndroidJUnit4Builder;
+ }
+
+ @Override
+ protected JUnit3Builder junit3Builder() {
+ return mAndroidJUnit3Builder;
+ }
+
+ @Override
+ protected AnnotatedBuilder annotatedBuilder() {
+ return mAndroidAnnotatedBuilder;
+ }
+
+ @Override
+ protected IgnoredBuilder ignoredBuilder() {
+ return mIgnoredBuilder;
+ }
+
+ @Override
+ protected RunnerBuilder suiteMethodBuilder() {
+ return mAndroidSuiteBuilder;
+ }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java
new file mode 100644
index 0000000..05c6623
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.util.AndroidRunnerParams;
+import android.support.test.runner.AndroidJUnit4;
+import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.JUnit4;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Extends {@link AndroidAnnotatedBuilder} to add support for passing the
+ * {@link AndroidRunnerParams} object to the constructor of any {@link RunnerBuilder}
+ * implementation that is not a {@link BlockJUnit4ClassRunner}.
+ *
+ * <p>If {@link AndroidRunnerParams#isSkipExecution()} is {@code true} the super class will create
+ * a {@link RunnerBuilder} that will fire appropriate events as if the tests are being run but will
+ * not actually run the test. Unfortunately, when it does that it appears to assume that the runner
+ * extends {@link BlockJUnit4ClassRunner}, returns a skipping {@link RunnerBuilder} appropriate for
+ * that and ignores the actual {@code runnerClass}. That is a problem because it will not work for
+ * custom {@link RunnerBuilder} instances that do not extend {@link BlockJUnit4ClassRunner}.
+ *
+ * <p>Therefore, when skipping execution this does some additional checks to make sure that the
+ * {@code runnerClass} does extend {@link BlockJUnit4ClassRunner} before calling the overridden
+ * method.
+ *
+ * <p>It then attempts to construct a {@link RunnerBuilder} by calling the constructor with the
+ * signature {@code <init>(Class, AndroidRunnerParams)}. If that doesn't exist it falls back to
+ * the overridden behavior.
+ */
+class ExtendedAndroidAnnotatedBuilder extends AndroidAnnotatedBuilder {
+
+ private final AndroidRunnerParams runnerParams;
+
+ public ExtendedAndroidAnnotatedBuilder(RunnerBuilder suiteBuilder,
+ AndroidRunnerParams runnerParams) {
+ super(suiteBuilder, runnerParams);
+ this.runnerParams = runnerParams;
+ }
+
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Exception {
+
+ RunWith annotation = testClass.getAnnotation(RunWith.class);
+ if (annotation != null) {
+ Class<? extends Runner> runnerClass = annotation.value();
+
+ // If the runner is expected to skip execution and it is a JUnit4, AndroidJUnit4 or
+ // a JUnit3 test class then return a special skipping runner.
+ if (runnerParams.isSkipExecution()) {
+ if (runnerClass == AndroidJUnit4.class || runnerClass == JUnit4.class
+ || TestCase.class.isAssignableFrom(testClass)) {
+ return super.runnerForClass(testClass);
+ }
+ }
+
+ try {
+ // try to build an AndroidJUnit4 runner
+ Runner runner = buildAndroidRunner(runnerClass, testClass);
+ if (runner != null) {
+ return runner;
+ }
+ } catch (NoSuchMethodException e) {
+ // let the super class handle the error for us and throw an InitializationError
+ // exception.
+ return super.buildRunner(runnerClass, testClass);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
new file mode 100644
index 0000000..ed16318
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.util.AndroidRunnerParams;
+import org.junit.internal.builders.AnnotatedBuilder;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Extends {@link AndroidRunnerBuilder} in order to provide alternate {@link RunnerBuilder}
+ * implementations.
+ */
+public class ExtendedAndroidRunnerBuilder extends AndroidRunnerBuilder {
+
+ private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
+
+ /**
+ * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
+ */
+ public ExtendedAndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
+ super(runnerParams);
+ mAndroidAnnotatedBuilder = new ExtendedAndroidAnnotatedBuilder(this, runnerParams);
+ }
+
+ @Override
+ protected AnnotatedBuilder annotatedBuilder() {
+ return mAndroidAnnotatedBuilder;
+ }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
new file mode 100644
index 0000000..3ccec3c
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Contains all the changes needed to the {@code android.support.test.internal.runner} classes.
+ *
+ * <p>As its name suggests {@code android.support.test.internal.runner} are internal classes that
+ * are not designed to be extended from outside those packages. This package encapsulates all the
+ * workarounds needed to overcome that limitation, from duplicating classes to using reflection.
+ * The intention is that these changes are temporary and they (or a better equivalent) will be
+ * quickly integrated into the internal classes.
+ */
+package com.android.cts.core.runner.support;
diff --git a/tests/deviceadmin/Android.mk b/tests/deviceadmin/Android.mk
new file mode 100644
index 0000000..3d02f9c
--- /dev/null
+++ b/tests/deviceadmin/Android.mk
@@ -0,0 +1,17 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/deviceadmin/deviceadminapp/Android.mk b/tests/deviceadmin/deviceadminapp/Android.mk
new file mode 100644
index 0000000..6ee3943
--- /dev/null
+++ b/tests/deviceadmin/deviceadminapp/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsEmptyDeviceAdmin
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
+
+LOCAL_SDK_VERSION := current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/deviceadmin/deviceadminapp/AndroidManifest.xml b/tests/deviceadmin/deviceadminapp/AndroidManifest.xml
new file mode 100644
index 0000000..9ce61a6
--- /dev/null
+++ b/tests/deviceadmin/deviceadminapp/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.devicepolicy.cts.emptydeviceadmin" >
+
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="24"/>
+
+ <application>
+ <receiver
+ android:name=".EmptyDeviceAdmin"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ >
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/deviceadmin/deviceadminapp/res/xml/device_admin.xml b/tests/deviceadmin/deviceadminapp/res/xml/device_admin.xml
new file mode 100644
index 0000000..c601371
--- /dev/null
+++ b/tests/deviceadmin/deviceadminapp/res/xml/device_admin.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+ <uses-policies>
+ <limit-password />
+ <watch-login />
+ <reset-password />
+ <force-lock />
+ <wipe-data />
+ <expire-password />
+ <encrypted-storage />
+ <disable-camera />
+ <disable-keyguard-features />
+ </uses-policies>
+</device-admin>
diff --git a/tests/deviceadmin/deviceadminapp/src/android/devicepolicy/cts/emptydeviceadmin/EmptyDeviceAdmin.java b/tests/deviceadmin/deviceadminapp/src/android/devicepolicy/cts/emptydeviceadmin/EmptyDeviceAdmin.java
new file mode 100644
index 0000000..82339ef
--- /dev/null
+++ b/tests/deviceadmin/deviceadminapp/src/android/devicepolicy/cts/emptydeviceadmin/EmptyDeviceAdmin.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.devicepolicy.cts.emptydeviceadmin;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class EmptyDeviceAdmin extends DeviceAdminReceiver {
+}
diff --git a/tests/deviceadmin/uninstalltest/Android.mk b/tests/deviceadmin/uninstalltest/Android.mk
new file mode 100644
index 0000000..ceee809
--- /dev/null
+++ b/tests/deviceadmin/uninstalltest/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsDeviceAdminUninstallerTestCases
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator android-support-test
+
+LOCAL_SDK_VERSION := current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/deviceadmin/uninstalltest/AndroidManifest.xml b/tests/deviceadmin/uninstalltest/AndroidManifest.xml
new file mode 100644
index 0000000..52a681a
--- /dev/null
+++ b/tests/deviceadmin/uninstalltest/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.devicepolicy.cts.uiautomatertest" >
+
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="24"/>
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:functionalTest="true"
+ android:targetPackage="android.devicepolicy.cts.uiautomatertest"
+ android:label="Device Admin Uninstall CTS tests"/>
+</manifest>
diff --git a/tests/deviceadmin/uninstalltest/AndroidTest.xml b/tests/deviceadmin/uninstalltest/AndroidTest.xml
new file mode 100644
index 0000000..51615f7
--- /dev/null
+++ b/tests/deviceadmin/uninstalltest/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for the CTS device admin uninstall tests">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsEmptyDeviceAdmin.apk" />
+ <option name="test-file-name" value="CtsDeviceAdminUninstallerTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="dpm set-active-admin --user cur android.devicepolicy.cts.emptydeviceadmin/.EmptyDeviceAdmin" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.devicepolicy.cts.uiautomatertest" />
+ </test>
+
+</configuration>
\ No newline at end of file
diff --git a/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java b/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java
new file mode 100644
index 0000000..23b3755
--- /dev/null
+++ b/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.devicepolicy.cts.uiautomatertest;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.provider.Settings;
+import android.widget.ScrollView;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.LargeTest;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DeviceAdminUninstallTest {
+
+ private static final String DEVICE_ADMIN_PACKAGE_NAME =
+ "android.devicepolicy.cts.emptydeviceadmin";
+ private static final String URI_PACKAGE_PREFIX = "package:";
+
+ private static final UiSelector DEACTIVATE_AND_UNINSTALL_BUTTON_SELECTOR = new UiSelector()
+ .resourceId("com.android.settings:id/action_button");
+ private static final UiSelector UNINSTALL_BUTTON_SELECTOR = new UiSelector()
+ .resourceId("com.android.settings:id/left_button");
+ private static final BySelector UNINSTALL_BUTTON_BYSELECTOR = By
+ .res("com.android.settings", "left_button");
+ private static final UiSelector OK_BUTTON_SELECTOR = new UiSelector()
+ .resourceId("android:id/button1");
+ private static final long DEACTIVATE_ADMIN_TIMEOUT = 15000;
+ private static final long WAIT_FOR_ACTIVITY_TIMEOUT = 6000;
+
+ private UiDevice mUiDevice;
+ private Context mContext;
+ private DevicePolicyManager mDpm;
+ private PackageManager mPm;
+
+ @Before
+ public void setUp() throws Exception {
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mContext = InstrumentationRegistry.getTargetContext();
+ mDpm = mContext.getSystemService(DevicePolicyManager.class);
+ mPm = mContext.getPackageManager();
+ }
+
+ private boolean hasActiveAdmin() {
+ final List<ComponentName> activeAdmins = mDpm.getActiveAdmins();
+ if (activeAdmins == null) {
+ return false;
+ }
+ for (ComponentName activeAdmin : activeAdmins) {
+ if (DEVICE_ADMIN_PACKAGE_NAME.equals(activeAdmin.getPackageName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void waitTillNoActiveAdmin() {
+ boolean interrupted = false;
+ final long timeOut = System.currentTimeMillis() + DEACTIVATE_ADMIN_TIMEOUT;
+ while (hasActiveAdmin() && System.currentTimeMillis() <= timeOut) {
+ try {
+ Thread.sleep(2500);
+ } catch (InterruptedException err) {
+ interrupted = true;
+ }
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ Assert.assertFalse(
+ "Package " + DEVICE_ADMIN_PACKAGE_NAME + " still has an active device admin",
+ hasActiveAdmin());
+ }
+
+ private boolean packageExists() {
+ PackageInfo packageInfo = null;
+ try {
+ packageInfo = mPm.getPackageInfo(DEVICE_ADMIN_PACKAGE_NAME, 0);
+ } catch (NameNotFoundException exc) {
+ }
+ return packageInfo != null;
+ }
+
+ private void launchApplicationDetailsActivity() {
+ final Uri packageURI = Uri.parse(URI_PACKAGE_PREFIX + DEVICE_ADMIN_PACKAGE_NAME);
+ final Intent displayAppDetailsIntent = new Intent(
+ Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ packageURI);
+ displayAppDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(displayAppDetailsIntent);
+ }
+
+ private void automateUninstallThroughUi() {
+ StringBuilder failMessageBuilder = new StringBuilder();
+ UiObject uninstallButton = mUiDevice
+ .findObject(UNINSTALL_BUTTON_SELECTOR);
+ UiScrollable scrollable = new UiScrollable(new UiSelector().className(ScrollView.class));
+ UiObject deactivateButton = mUiDevice
+ .findObject(DEACTIVATE_AND_UNINSTALL_BUTTON_SELECTOR);
+ UiObject okButton = mUiDevice
+ .findObject(OK_BUTTON_SELECTOR);
+ mUiDevice.wait(Until.hasObject(UNINSTALL_BUTTON_BYSELECTOR), WAIT_FOR_ACTIVITY_TIMEOUT);
+ try {
+ uninstallButton.clickAndWaitForNewWindow();
+ scrollable.scrollIntoView(DEACTIVATE_AND_UNINSTALL_BUTTON_SELECTOR);
+ deactivateButton.clickAndWaitForNewWindow();
+ waitTillNoActiveAdmin();
+ okButton.clickAndWaitForNewWindow();
+ } catch (UiObjectNotFoundException exc) {
+ failMessageBuilder.append(exc.getMessage());
+ } finally {
+ Assert.assertFalse(
+ "Package " + DEVICE_ADMIN_PACKAGE_NAME + " was not uninstalled.\n"
+ + failMessageBuilder.toString(), packageExists());
+ }
+ }
+
+ @Test
+ public void uninstallPackageWithActiveAdmin() {
+ Assert.assertTrue("Package " + DEVICE_ADMIN_PACKAGE_NAME + " was not found installed",
+ packageExists());
+ Assert.assertTrue("Package " + DEVICE_ADMIN_PACKAGE_NAME
+ + " does not have any active admin component", hasActiveAdmin());
+ launchApplicationDetailsActivity();
+ automateUninstallThroughUi();
+ }
+}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 56475fd..9b3a09d 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -158,6 +158,14 @@
bug: 17508787
},
{
+ description: "This test is not working on Android Player",
+ names: [
+ "com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions",
+ "com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions"
+ ],
+ bug: 27949133
+},
+{
description: "Test is not yet properly implemented",
names: [
"android.voicesettings.cts.ZenModeTest#testAll"
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index 86bc616..ae790fb 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -14,12 +14,6 @@
limitations under the License.
-->
<configuration description="Config for CTS Sample test cases">
- <target_preparer class=
- "com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsSampleDeviceTestCases" />
- <option name="version" value="1.0" />
- </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSampleDeviceTestCases.apk" />
diff --git a/tests/sample/DynamicConfig.xml b/tests/sample/DynamicConfig.xml
deleted file mode 100644
index 515dc01..0000000
--- a/tests/sample/DynamicConfig.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<dynamicConfig>
- <entry key="report-log-name">
- <value>SampleTestMetrics</value>
- </entry>
- <entry key="testMultiplication-stream-name">
- <value>testMultiplicationMetrics</value>
- </entry>
- <entry key="testCountUp-stream-name">
- <value>testCountUpMetrics</value>
- </entry>
- <entry key="testCountDown-stream-name">
- <value>testCountDownMetrics</value>
- </entry>
- <entry key="testSort-stream-name">
- <value>testSortMetrics</value>
- </entry>
-</dynamicConfig>
\ No newline at end of file
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
index 8985bd6..7f8e2f6 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
@@ -19,7 +19,6 @@
import android.test.ActivityInstrumentationTestCase2;
import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
@@ -32,16 +31,6 @@
extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
/**
- * The default name for metrics report log file.
- */
- private String DEFAULT_REPORT_LOG_NAME = "DefaultMetrics";
-
- /**
- * The default name for a metrics stream.
- */
- private String DEFAULT_STREAM_NAME = "DefaultStream";
-
- /**
* Sample numbers used by the sample tests.
*/
private static final int MULTIPLICATION_NUMBER_1 = 23;
@@ -50,10 +39,10 @@
private static final int COUNT_START = 1;
private static final int COUNT_END = 1000;
- private static final String EXPECTED_PRODUCT_TAG = "Expected Product";
- private static final String ACTUAL_PRODUCT_TAG = "Actual Product";
- private static final String START_TAG = "Count Start";
- private static final String END_TAG = "Actual End";
+ private static final String EXPECTED_PRODUCT_TAG = "expected_product";
+ private static final String ACTUAL_PRODUCT_TAG = "actual_product";
+ private static final String START_TAG = "count_start";
+ private static final String END_TAG = "actual_end";
/**
* Constructor which passes the class of the activity to be instrumented.
@@ -71,8 +60,8 @@
assertTrue("Multiplication result do not match", product == MULTIPLICATION_RESULT);
// Log metrics from the test.
- String reportLogName = getReportLogName();
- String streamName = getStreamName("testMultiplication-stream-name");
+ String reportLogName = "SampleDeviceTestMetrics";
+ String streamName = "test_multiplication_metrics";
DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
reportLog.addValue(EXPECTED_PRODUCT_TAG, 1.0 * MULTIPLICATION_RESULT, ResultType.NEUTRAL,
ResultUnit.NONE);
@@ -85,7 +74,7 @@
* Sample test to check counting up.
*/
public void testCountUp() {
- String streamName = getStreamName("testCountUp-stream-name");
+ String streamName = "test_count_up_metrics";
countHelper(1, streamName);
}
@@ -93,7 +82,7 @@
* Sample test to check counting down.
*/
public void testCountDown() {
- String streamName = getStreamName("testCountDown-stream-name");
+ String streamName = "test_count_down_metrics";
countHelper(2, streamName);
}
@@ -122,45 +111,11 @@
}
// Log metrics.
- String reportLogName = getReportLogName();
+ String reportLogName = "SampleDeviceTestMetrics";
DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
- reportLog.addValue(streamName + START_TAG, 1.0 * start, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(streamName + END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.setSummary(streamName + END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue(START_TAG, 1.0 * start, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue(END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.setSummary(END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
reportLog.submit(getInstrumentation());
}
-
- /**
- * Retreives name of report log from dynamic config.
- *
- * @return {@link String} name of the report log.
- */
- private String getReportLogName() {
- try {
- DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
- "CtsSampleDeviceTestCases");
- return dynamicConfig.getValues("report-log-name").get(0);
- } catch (Exception e) {
- // Do nothing.
- }
- return DEFAULT_REPORT_LOG_NAME ;
- }
-
-
- /**
- * Retreives name of metrics stream from dynamic config.
- *
- * @param key The key in dynamic config containing stream name.
- * @return {@link String} name of the stream.
- */
- private String getStreamName(String key) {
- try {
- DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
- "CtsSampleDeviceTestCases");
- return dynamicConfig.getValues(key).get(0);
- } catch (Exception e) {
- // Do nothing.
- }
- return DEFAULT_STREAM_NAME ;
- }
}
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
index 2f6ce78..f8f7a6b 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
@@ -19,7 +19,6 @@
import android.test.ActivityInstrumentationTestCase2;
import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
import com.android.compatibility.common.util.MeasureRun;
import com.android.compatibility.common.util.MeasureTime;
import com.android.compatibility.common.util.ResultType;
@@ -37,16 +36,6 @@
public class SampleDeviceResultTest extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
/**
- * The default name for metrics report log file.
- */
- private String DEFAULT_REPORT_LOG_NAME = "DefaultMetrics";
-
- /**
- * The default name for a metrics stream.
- */
- private String DEFAULT_STREAM_NAME = "DefaultStream";
-
- /**
* The number of times to repeat the test.
*/
private static final int REPEAT = 5;
@@ -87,15 +76,15 @@
// Compute the stats.
Stat.StatResult stat = Stat.getStat(result);
// Create a new report to hold the metrics.
- String reportLogName = getReportLogName();
- String streamName = getStreamName("testSort-stream-name");
+ String reportLogName = "SampleDeviceTestMetrics";
+ String streamName = "test_sort_metrics";
DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
// Add the results to the report.
- reportLog.addValues("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
- reportLog.addValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
- reportLog.addValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
+ reportLog.addValues("times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+ reportLog.addValue("min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
+ reportLog.addValue("max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
// Every report must have a summary,
- reportLog.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+ reportLog.setSummary("average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
// Submit the report to the given instrumentation.
reportLog.submit(getInstrumentation());
}
@@ -123,39 +112,4 @@
}
return true;
}
-
- /**
- * Retreives name of report log from dynamic config.
- *
- * @return {@link String} name of the report log.
- */
- private String getReportLogName() {
- try {
- DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
- "CtsSampleDeviceTestCases");
- return dynamicConfig.getValues("report-log-name").get(0);
- } catch (Exception e) {
- // Do nothing.
- }
- return DEFAULT_REPORT_LOG_NAME;
- }
-
- /**
- * Retreives name of metrics stream from dynamic config.
- *
- * @param key The key in dynamic config containing stream name.
- * @return {@link String} name of the stream.
- */
- private String getStreamName(String key) {
- try {
- DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
- "CtsSampleDeviceTestCases");
- return dynamicConfig.getValues(key).get(0);
- } catch (Exception e) {
- // Do nothing.
- }
- return DEFAULT_STREAM_NAME ;
- }
-
-
}
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
new file mode 100644
index 0000000..08201a6
--- /dev/null
+++ b/tests/tests/app/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsAndroidAppTestCases
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml
new file mode 100644
index 0000000..be903e3
--- /dev/null
+++ b/tests/tests/app/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.cts">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".ApplyOverrideConfigurationActivity"
+ android:configChanges="orientation|screenSize" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.app.cts"
+ android:label="CTS tests of android.app">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/app/AndroidTest.xml b/tests/tests/app/AndroidTest.xml
new file mode 100644
index 0000000..739e0ba
--- /dev/null
+++ b/tests/tests/app/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Configuration for app Tests">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsAndroidAppTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.app.cts" />
+ <option name="runtime-hint" value="1s" />
+ </test>
+</configuration>
diff --git a/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationActivity.java b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationActivity.java
new file mode 100644
index 0000000..305d0a8
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.app.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+
+public class ApplyOverrideConfigurationActivity extends Activity {
+ public static final int OVERRIDE_SMALLEST_WIDTH = 99999;
+
+ private CompletableFuture<Configuration> mOnConfigurationChangedFuture = null;
+
+ @Override
+ protected void attachBaseContext(Context newBase) {
+ super.attachBaseContext(newBase);
+
+ final Configuration overrideConfig = new Configuration();
+ overrideConfig.smallestScreenWidthDp = OVERRIDE_SMALLEST_WIDTH;
+ applyOverrideConfiguration(overrideConfig);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ synchronized (this) {
+ if (mOnConfigurationChangedFuture != null) {
+ mOnConfigurationChangedFuture.complete(new Configuration(newConfig));
+ mOnConfigurationChangedFuture = null;
+ }
+ }
+ }
+
+ /**
+ * Hands back a Future that will be completed when onConfigurationChanged() is called.
+ * It will only report a single call to onConfigurationChanged(). Subsequent calls can be
+ * captured by calling this method again. Calling this method will cancel all past
+ * Futures received from this method.
+ * @return A Future that completes with the configuration passed in to onConfigurationChanged().
+ */
+ public synchronized Future<Configuration> watchForSingleOnConfigurationChangedCallback() {
+ if (mOnConfigurationChangedFuture != null) {
+ mOnConfigurationChangedFuture.cancel(true);
+ }
+
+ mOnConfigurationChangedFuture = new CompletableFuture<>();
+ return mOnConfigurationChangedFuture;
+ }
+}
diff --git a/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationTest.java b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationTest.java
new file mode 100644
index 0000000..a8f1473
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.app.cts;
+
+import android.app.UiAutomation;
+import android.content.res.Configuration;
+import android.support.test.filters.SmallTest;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.util.concurrent.Future;
+
+/**
+ * Tests the {@link android.view.ContextThemeWrapper#applyOverrideConfiguration(Configuration)}
+ * method and how it affects the Activity's resources and lifecycle callbacks.
+ */
+public class ApplyOverrideConfigurationTest extends
+ ActivityInstrumentationTestCase2<ApplyOverrideConfigurationActivity> {
+ public ApplyOverrideConfigurationTest() {
+ super(ApplyOverrideConfigurationActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+ super.tearDown();
+ }
+
+ @SmallTest
+ public void testOverriddenConfigurationIsPassedIntoCallback() throws Exception {
+ final Configuration config = getActivity().getResources().getConfiguration();
+ final int originalOrientation = config.orientation;
+ assertEquals(ApplyOverrideConfigurationActivity.OVERRIDE_SMALLEST_WIDTH,
+ config.smallestScreenWidthDp);
+
+ Future<Configuration> callback =
+ getActivity().watchForSingleOnConfigurationChangedCallback();
+
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
+
+ final Configuration callbackConfig = callback.get();
+ assertNotNull(callbackConfig);
+
+ final Configuration newConfig = getActivity().getResources().getConfiguration();
+ assertTrue(newConfig.orientation != originalOrientation);
+ assertEquals(ApplyOverrideConfigurationActivity.OVERRIDE_SMALLEST_WIDTH,
+ newConfig.smallestScreenWidthDp);
+
+ assertEquals(newConfig, callbackConfig);
+ }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index c21bc9c..d0a00c9 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -79,7 +79,7 @@
}
}
- public void testAssistStructure() throws Exception {
+ public void testAssistStructure() throws Throwable {
if (mActivityManager.isLowRamDevice()) {
Log.d(TAG, "Not running assist tests on low-RAM device.");
return;
@@ -90,10 +90,14 @@
waitForOnResume();
startSession();
waitForContext();
- verifyAssistDataNullness(false, false, false, false);
-
- verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
- false /*FLAG_SECURE set*/);
+ getInstrumentation().waitForIdleSync();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ verifyAssistDataNullness(false, false, false, false);
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false /*FLAG_SECURE set*/);
+ }
+ });
}
private class AssistStructureTestBroadcastReceiver extends BroadcastReceiver {
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index dcd350e..aa8348a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -1189,6 +1189,13 @@
assertEquals(0.0f, width);
}
{
+ for (int i = 0; i < string.length(); i++) {
+ final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
+ false, i);
+ assertEquals(0.0f, width);
+ }
+ }
+ {
final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0,
string.length(), false, string.length() / 2);
final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0,
@@ -1203,11 +1210,32 @@
string.length(), false, string.length());
assertTrue(widthFromHead > widthFromSecond);
}
+ {
+ float width = 0.0f;
+ for (int i = 0; i < string.length(); i++) {
+ width += p.getRunAdvance(string, i, i + 1, 0, string.length(), false, i + 1);
+ }
+ final float totalWidth = p.getRunAdvance(string, 0, string.length(), 0,
+ string.length(), false, string.length());
+ assertEquals(totalWidth, width, 1.0f);
+ }
}
{
// RTL
String string = "\u0644\u063A\u0629 \u0639\u0631\u0628\u064A\u0629"; // Arabic
{
+ final float width = p.getRunAdvance(string, 0, string.length(), 0,
+ string.length(), true, 0);
+ assertEquals(0.0f, width);
+ }
+ {
+ for (int i = 0; i < string.length(); i++) {
+ final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
+ true, i);
+ assertEquals(0.0f, width);
+ }
+ }
+ {
final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0,
string.length(), true, string.length() / 2);
final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0,
diff --git a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
index c991b6f..8bbf448 100644
--- a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -135,6 +135,54 @@
mActivity.getAepEs31Support());
}
+ public void testOpenGlEsVersionForVrHighPerformance() throws InterruptedException {
+ if (!supportsVrHighPerformance())
+ return;
+ restartActivityWithClientVersion(3);
+
+ int reportedVersion = getVersionFromActivityManager(mActivity);
+ int major = getMajorVersion(reportedVersion);
+ int minor = getMinorVersion(reportedVersion);
+
+ assertTrue("OpenGL ES version 3.2 or higher is required for VR high-performance devices " +
+ " but this device supports only version " + major + "." + minor,
+ (major == 3 && minor >= 2) || major > 3);
+ }
+
+ public void testRequiredExtensionsForVrHighPerformance() throws InterruptedException {
+ if (!supportsVrHighPerformance())
+ return;
+ restartActivityWithClientVersion(3);
+
+ String extensions = mActivity.getExtensionsString();
+ final String requiredList[] = {
+ "EXT_protected_textures",
+ "EXT_multisampled_render_to_texture",
+ "OVR_multiview",
+ "OVR_multiview_multisampled_render_to_texture",
+ "OVR_multiview2",
+ };
+
+ for (int i = 0; i < requiredList.length; ++i) {
+ assertTrue("Required extension for VR high-performance is missing: " + requiredList[i],
+ hasExtension(extensions, requiredList[i]));
+ }
+
+ EGL10 egl = (EGL10) EGLContext.getEGL();
+ EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ extensions = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS);
+ final String requiredEglList[] = {
+ "EGL_ANDROID_front_buffer_auto_refresh",
+ "EGL_EXT_protected_content",
+ "EGL_KHR_mutable_render_buffer",
+ };
+
+ for (int i = 0; i < requiredList.length; ++i) {
+ assertTrue("Required EGL extension for VR high-performance is missing: " +
+ requiredEglList[i], hasExtension(extensions, requiredEglList[i]));
+ }
+ }
+
private static boolean hasExtension(String extensions, String name) {
return OpenGlEsVersionCtsActivity.hasExtension(extensions, name);
}
@@ -264,4 +312,13 @@
setActivityIntent(null);
}
}
+
+ /**
+ * Return whether the system supports FEATURE_VR_MODE and
+ * FEATURE_VR_MODE_HIGH_PERFORMANCE. This is used to skip some tests.
+ */
+ private boolean supportsVrHighPerformance() {
+ PackageManager pm = mActivity.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
+ }
}
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 39a4b53..6f183d5 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -31,9 +31,7 @@
# The aim of this package is to run tests against the implementation in use by
# the current android system.
LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util \
- android-support-test \
- vogarexpect \
+ cts-core-test-runner \
android-icu4j-tests
# Tag this module as a cts test artifact
diff --git a/tests/tests/icu/AndroidManifest.xml b/tests/tests/icu/AndroidManifest.xml
index 7d99c0a..c743375 100644
--- a/tests/tests/icu/AndroidManifest.xml
+++ b/tests/tests/icu/AndroidManifest.xml
@@ -22,7 +22,7 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.icu.cts.IcuTestRunner"
+ <instrumentation android:name="com.android.cts.core.runner.CoreTestRunner"
android:targetPackage="android.icu.cts"
- android:label="ICU4J library tests."/>
+ android:label="CTS Repackaged ICU4J library tests."/>
</manifest>
diff --git a/tests/tests/icu/AndroidTest.xml b/tests/tests/icu/AndroidTest.xml
index 18c95cd..769b789 100644
--- a/tests/tests/icu/AndroidTest.xml
+++ b/tests/tests/icu/AndroidTest.xml
@@ -18,8 +18,13 @@
<option name="test-file-name" value="CtsIcuTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="runner" value="android.icu.cts.IcuTestRunner" /><!-- override AJUR -->
+ <!-- override AJUR -->
+ <option name="runner" value="com.android.cts.core.runner.CoreTestRunner" />
<option name="package" value="android.icu.cts" />
+ <option name="instrumentation-arg" key="core-root-classes"
+ value="android.icu.cts.coverage.TestAll,android.icu.dev.test.TestAll" />
+ <option name="instrumentation-arg" key="core-expectations"
+ value="/android/icu/cts/expectations/icu-known-failures.txt" />
<option name="runtime-hint" value="30m19s" />
</test>
</configuration>
diff --git a/tests/tests/icu/test-list.txt b/tests/tests/icu/test-list.txt
index 84da3c4..cd47a76 100644
--- a/tests/tests/icu/test-list.txt
+++ b/tests/tests/icu/test-list.txt
@@ -1,3 +1,37 @@
+android.icu.cts.coverage.lang.UCharacterTest#testNameAliasing
+android.icu.cts.coverage.lang.UCharacterTest#testToTitleCase_Locale_String_BreakIterator_I
+android.icu.cts.coverage.lang.UCharacterTest#testToTitleCase_String_BreakIterator_en
+android.icu.cts.coverage.lang.UCharacterTest#testToTitleCase_String_BreakIterator_nl
+android.icu.cts.coverage.text.AlphabeticIndexTest#testAddLabels_Locale
+android.icu.cts.coverage.text.AlphabeticIndexTest#testFlowLabels
+android.icu.cts.coverage.text.AlphabeticIndexTest#testGetRecordCount_empty
+android.icu.cts.coverage.text.AlphabeticIndexTest#testGetRecordCount_withRecords
+android.icu.cts.coverage.text.DateFormatSymbolsTest#testSetEraNames_defensivelyCopies
+android.icu.cts.coverage.text.DateFormatSymbolsTest#testYearNames_defensivelyCopies
+android.icu.cts.coverage.text.DateIntervalFormatTest#testGetInstance_String_DateIntervalInfo
+android.icu.cts.coverage.text.DateIntervalFormatTest#testGetInstance_String_Locale_DateIntervalInfo
+android.icu.cts.coverage.text.DateIntervalFormatTest#testParseObject_notSupported
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testGetInstance
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testGetLocale
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testKeyDisplayName
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testKeyValueDisplayName
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testLocaleDisplayName
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testScriptDisplayName_Int
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testScriptDisplayName_String
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testVariantDisplayName
+android.icu.cts.coverage.text.RelativeDateTimeFormatterTest#testGetInstance
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetAvailableMetaZoneIDs
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetAvailableMetaZoneIDs_String
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetInstance_Locale
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetMetaZoneDisplayName
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetMetaZoneID
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetTimeZoneDisplayName
+android.icu.cts.coverage.text.UnicodeSetTest#testAddAll_CharacterSequences
+android.icu.cts.coverage.text.UnicodeSetTest#testCompareTo
+android.icu.cts.coverage.util.CurrencyTest#testGetDefaultFractionDigits_CurrencyUsage
+android.icu.cts.coverage.util.CurrencyTest#testGetName_Locale_Int_String_BooleanArray
+android.icu.cts.coverage.util.CurrencyTest#testGetRoundingIncrement
+android.icu.cts.coverage.util.CurrencyTest#testGetRoundingIncrement_CurrencyUsage
android.icu.dev.test.bidi.BiDiConformanceTest#TestBidiCharacterTest
android.icu.dev.test.bidi.BiDiConformanceTest#TestBidiTest
android.icu.dev.test.bidi.TestBidi#testBidi
@@ -164,6 +198,7 @@
android.icu.dev.test.calendar.IBMCalendarTest#TestLeapFieldDifference
android.icu.dev.test.calendar.IBMCalendarTest#TestMalaysianInstance
android.icu.dev.test.calendar.IBMCalendarTest#TestRepeatedWallTime
+android.icu.dev.test.calendar.IBMCalendarTest#TestSimpleDateFormatCoverage
android.icu.dev.test.calendar.IBMCalendarTest#TestSkippedWallTime
android.icu.dev.test.calendar.IBMCalendarTest#TestTaiwan
android.icu.dev.test.calendar.IBMCalendarTest#TestTaiwanCoverage
@@ -178,6 +213,7 @@
android.icu.dev.test.calendar.IndianTest#TestBasic
android.icu.dev.test.calendar.IndianTest#TestCases
android.icu.dev.test.calendar.IndianTest#TestCoverage
+android.icu.dev.test.calendar.IndianTest#TestCoverage12424
android.icu.dev.test.calendar.IndianTest#TestLimits
android.icu.dev.test.calendar.IndianTest#TestYear
android.icu.dev.test.calendar.IndianTest#TestYearEdge
@@ -198,6 +234,7 @@
android.icu.dev.test.calendar.JapaneseTest#TestCoverage
android.icu.dev.test.calendar.JapaneseTest#TestJapaneseYear3282
android.icu.dev.test.calendar.JapaneseTest#TestLimits
+android.icu.dev.test.calendar.PersianTest#TestCoverage12424
android.icu.dev.test.calendar.PersianTest#TestMapping
android.icu.dev.test.charsetdet.TestCharsetDetector#TestArabic
android.icu.dev.test.charsetdet.TestCharsetDetector#TestBufferOverflow
@@ -875,6 +912,7 @@
android.icu.dev.test.format.MeasureUnitTest#testOldFormatBadArg
android.icu.dev.test.format.MeasureUnitTest#testOldFormatWithArray
android.icu.dev.test.format.MeasureUnitTest#testOldFormatWithList
+android.icu.dev.test.format.MeasureUnitTest#testParseObject
android.icu.dev.test.format.MeasureUnitTest#TestSerial
android.icu.dev.test.format.MeasureUnitTest#TestSerialFormatWidthEnum
android.icu.dev.test.format.MeasureUnitTest#testSimplePer
@@ -969,6 +1007,7 @@
android.icu.dev.test.format.NumberFormatTest#TestFieldPositionFractionButInteger
android.icu.dev.test.format.NumberFormatTest#TestFieldPositionInteger
android.icu.dev.test.format.NumberFormatTest#TestFormat
+android.icu.dev.test.format.NumberFormatTest#TestFormatAbstractImplCoverage
android.icu.dev.test.format.NumberFormatTest#TestFormatToCharacterIteratorIssue11805
android.icu.dev.test.format.NumberFormatTest#TestFormatToCharacterIteratorThread
android.icu.dev.test.format.NumberFormatTest#TestGetAvailableLocales
@@ -983,6 +1022,7 @@
android.icu.dev.test.format.NumberFormatTest#TestNegZeroRounding
android.icu.dev.test.format.NumberFormatTest#TestNumberFormatFactory
android.icu.dev.test.format.NumberFormatTest#TestNumberFormatTestTupleToString
+android.icu.dev.test.format.NumberFormatTest#TestNumberingSystemCoverage
android.icu.dev.test.format.NumberFormatTest#TestNumberingSystems
android.icu.dev.test.format.NumberFormatTest#TestPad
android.icu.dev.test.format.NumberFormatTest#TestParse
@@ -1101,6 +1141,7 @@
android.icu.dev.test.format.PluralFormatUnitTest#TestApplyPatternAndFormat
android.icu.dev.test.format.PluralFormatUnitTest#TestConstructor
android.icu.dev.test.format.PluralFormatUnitTest#TestDecimals
+android.icu.dev.test.format.PluralFormatUnitTest#TestEquals
android.icu.dev.test.format.PluralFormatUnitTest#TestExtendedPluralFormat
android.icu.dev.test.format.PluralFormatUnitTest#TestExtendedPluralFormatParsing
android.icu.dev.test.format.PluralFormatUnitTest#TestNegative
@@ -1242,6 +1283,11 @@
android.icu.dev.test.format.TestMessageFormat#TestFormatToCharacterIterator
android.icu.dev.test.format.TestMessageFormat#TestGetFormatByArgumentName
android.icu.dev.test.format.TestMessageFormat#TestHashCode
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternAutoQuoteApostropheDeep
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternFreezable
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternNamedAndNumberedArguments
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternParseChoiceStyle
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternPartCoverage
android.icu.dev.test.format.TestMessageFormat#TestMsgFormatChoice
android.icu.dev.test.format.TestMessageFormat#testNamedArguments
android.icu.dev.test.format.TestMessageFormat#testNestedFormatsInPluralFormat
@@ -1282,10 +1328,13 @@
android.icu.dev.test.format.TimeUnitTest#TestSetup
android.icu.dev.test.format.TimeUnitTest#TestStandInForMeasureFormat
android.icu.dev.test.format.TimeUnitTest#TestTimeUnitFormat
+android.icu.dev.test.format.TimeZoneFormatTest#TestAPI
android.icu.dev.test.format.TimeZoneFormatTest#TestFormat
android.icu.dev.test.format.TimeZoneFormatTest#TestFormatTZDBNames
+android.icu.dev.test.format.TimeZoneFormatTest#TestInheritedFormat
android.icu.dev.test.format.TimeZoneFormatTest#TestISOFormat
android.icu.dev.test.format.TimeZoneFormatTest#TestParse
+android.icu.dev.test.format.TimeZoneFormatTest#TestParseCoverage
android.icu.dev.test.format.TimeZoneFormatTest#TestTimeRoundTrip
android.icu.dev.test.format.TimeZoneFormatTest#TestTimeZoneRoundTrip
android.icu.dev.test.format.TimeZoneFormatTest#TestTZDBNamesThreading
@@ -1482,6 +1531,7 @@
android.icu.dev.test.normalizer.BasicTest#TestDebugStatic
android.icu.dev.test.normalizer.BasicTest#TestDecomp
android.icu.dev.test.normalizer.BasicTest#TestExplodingBase
+android.icu.dev.test.normalizer.BasicTest#TestFCD
android.icu.dev.test.normalizer.BasicTest#TestFCNFKCClosure
android.icu.dev.test.normalizer.BasicTest#TestFilteredAppend
android.icu.dev.test.normalizer.BasicTest#TestFilteredNormalizer2
@@ -1492,7 +1542,11 @@
android.icu.dev.test.normalizer.BasicTest#TestGetRawDecomposition
android.icu.dev.test.normalizer.BasicTest#TestHangulCompose
android.icu.dev.test.normalizer.BasicTest#TestHangulDecomp
+android.icu.dev.test.normalizer.BasicTest#TestNFC
+android.icu.dev.test.normalizer.BasicTest#TestNFD
android.icu.dev.test.normalizer.BasicTest#TestNone
+android.icu.dev.test.normalizer.BasicTest#TestNoneNormalizer
+android.icu.dev.test.normalizer.BasicTest#TestNoopNormalizer2
android.icu.dev.test.normalizer.BasicTest#TestNormalizerAPI
android.icu.dev.test.normalizer.BasicTest#TestPreviousNext
android.icu.dev.test.normalizer.BasicTest#TestPreviousNextJCI
@@ -2156,7 +2210,10 @@
android.icu.dev.test.util.ULocaleTest#TestCoverage
android.icu.dev.test.util.ULocaleTest#TestDateFormat
android.icu.dev.test.util.ULocaleTest#TestDisplayKeyword
+android.icu.dev.test.util.ULocaleTest#TestDisplayLanguageWithDialectCoverage
android.icu.dev.test.util.ULocaleTest#TestDisplayNames
+android.icu.dev.test.util.ULocaleTest#TestDisplayNameWithDialectCoverage
+android.icu.dev.test.util.ULocaleTest#TestDisplayScriptCoverage
android.icu.dev.test.util.ULocaleTest#TestDisplayWithKeyword
android.icu.dev.test.util.ULocaleTest#TestExtension
android.icu.dev.test.util.ULocaleTest#TestForLanguageTag
diff --git a/tests/tests/location/Android.mk b/tests/tests/location/Android.mk
index 842a92d..6a8b9d3 100644
--- a/tests/tests/location/Android.mk
+++ b/tests/tests/location/Android.mk
@@ -16,6 +16,29 @@
include $(CLEAR_VARS)
+# Reusable Location test classes and helpers
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-location-tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil ctstestrunner
+
+LOCAL_SDK_VERSION := test_current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/android/location/cts)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# CtsLocationTestCases package
+
+include $(CLEAR_VARS)
+
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
# and when built explicitly put it in the data partition
diff --git a/tests/tests/location/src/android/location/cts/GnssClockTest.java b/tests/tests/location/src/android/location/cts/GnssClockTest.java
index e2ac503..b883f74 100644
--- a/tests/tests/location/src/android/location/cts/GnssClockTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssClockTest.java
@@ -18,9 +18,8 @@
import android.location.GnssClock;
import android.os.Parcel;
-import android.test.AndroidTestCase;
-public class GnssClockTest extends AndroidTestCase {
+public class GnssClockTest extends GnssTestCase {
public void testDescribeContents() {
GnssClock clock = new GnssClock();
clock.describeContents();
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java
index 00e0877..42e555d 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java
@@ -19,7 +19,6 @@
import android.location.GnssMeasurement;
import android.location.GnssMeasurementsEvent;
import android.location.GpsStatus;
-import android.test.AndroidTestCase;
import android.util.Log;
import java.util.List;
@@ -49,9 +48,9 @@
* 2.4.2 The test might fail in a future Android release, when this requirement
* becomes mandatory.
*/
-public class GnssMeasurementRegistrationTest extends AndroidTestCase {
+public class GnssMeasurementRegistrationTest extends GnssTestCase {
- private static final String TAG = "GpsMeasRegistrationTest";
+ private static final String TAG = "GnssMeasRegTest";
private TestLocationManager mTestLocationManager;
private static final int EVENTS_COUNT = 5;
private static final int GPS_EVENTS_COUNT = 1;
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
index 3ae7b3c..2fc63a8 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
@@ -19,9 +19,8 @@
import android.location.GnssMeasurement;
import android.location.GnssStatus;
import android.os.Parcel;
-import android.test.AndroidTestCase;
-public class GnssMeasurementTest extends AndroidTestCase {
+public class GnssMeasurementTest extends GnssTestCase {
public void testDescribeContents() {
GnssMeasurement measurement = new GnssMeasurement();
measurement.describeContents();
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java
index e8b8c74..ba6311f 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java
@@ -18,7 +18,6 @@
import android.location.GnssMeasurement;
import android.location.GnssMeasurementsEvent;
-import android.test.AndroidTestCase;
import android.util.Log;
import java.util.List;
@@ -39,7 +38,7 @@
* 5. Verify {@link GnssMeasurement}s (all mandatory fields), the test will fail if any of the
* mandatory fields is not populated or in the expected range.
*/
-public class GnssMeasurementValuesTest extends AndroidTestCase {
+public class GnssMeasurementValuesTest extends GnssTestCase {
private static final String TAG = "GnssMeasValuesTest";
private static final int LOCATION_TO_COLLECT_COUNT = 5;
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
index 7a2bead..b3cb0ab 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
@@ -19,7 +19,6 @@
import android.location.GnssMeasurement;
import android.location.GnssMeasurementsEvent;
import android.location.GpsStatus;
-import android.test.AndroidTestCase;
import android.util.Log;
import java.util.Arrays;
@@ -55,7 +54,7 @@
5. If {@link GnssMeasurementsEvent}s are received: verify all mandatory fields, the test will fail
if any of the mandatory fields is not populated or in the expected range.
*/
-public class GnssMeasurementWhenNoLocationTest extends AndroidTestCase {
+public class GnssMeasurementWhenNoLocationTest extends GnssTestCase {
private static final String TAG = "GnssMeasWhenNoFixTest";
private TestGnssMeasurementListener mMeasurementListener;
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
index 72addce..201a9e7 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
@@ -19,9 +19,8 @@
import android.location.GnssClock;
import android.location.GnssMeasurement;
import android.location.GnssMeasurementsEvent;
-import android.test.AndroidTestCase;
-public class GnssMeasurementsEventCallbackTest extends AndroidTestCase {
+public class GnssMeasurementsEventCallbackTest extends GnssTestCase {
private static class MockCallback extends GnssMeasurementsEvent.Callback {
}
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
index 51af03d..06f4e5f 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
@@ -21,12 +21,11 @@
import android.location.GnssMeasurementsEvent;
import android.location.GnssStatus;
import android.os.Parcel;
-import android.test.AndroidTestCase;
import java.util.Collection;
import java.util.Iterator;
-public class GnssMeasurementsEventTest extends AndroidTestCase {
+public class GnssMeasurementsEventTest extends GnssTestCase {
public void testDescribeContents() {
GnssClock clock = new GnssClock();
GnssMeasurement m1 = new GnssMeasurement();
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
index 0589c57..aa90a2f 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
@@ -18,9 +18,8 @@
import android.location.GnssNavigationMessage;
import android.location.GnssNavigationMessageEvent;
-import android.test.AndroidTestCase;
-public class GnssNavigationMessageEventCallbackTest extends AndroidTestCase {
+public class GnssNavigationMessageEventCallbackTest extends GnssTestCase {
private static class MockCallback extends GnssNavigationMessageEvent.Callback {
}
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
index 0772092..c8abb6e 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
@@ -19,9 +19,8 @@
import android.location.GnssNavigationMessage;
import android.location.GnssNavigationMessageEvent;
import android.os.Parcel;
-import android.test.AndroidTestCase;
-public class GnssNavigationMessageEventTest extends AndroidTestCase {
+public class GnssNavigationMessageEventTest extends GnssTestCase {
public void testDescribeContents() {
GnssNavigationMessage message = new GnssNavigationMessage();
GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java
index 5348470..4b87919 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java
@@ -18,7 +18,6 @@
import android.location.GnssNavigationMessage;
import android.location.GnssNavigationMessageEvent;
-import android.test.AndroidTestCase;
import android.util.Log;
import java.util.List;
@@ -48,7 +47,7 @@
* 2.4.2 The test might fail in a future Android release, when this requirement
* becomes mandatory.
*/
-public class GnssNavigationMessageRegistrationTest extends AndroidTestCase {
+public class GnssNavigationMessageRegistrationTest extends GnssTestCase {
private static final String TAG = "GpsNavMsgRegTest";
private TestLocationManager mTestLocationManager;
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
index 42a67b9..262232e 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
@@ -18,7 +18,6 @@
import android.location.GnssNavigationMessage;
import android.location.GnssNavigationMessageEvent;
-import android.test.AndroidTestCase;
import android.os.Parcel;
import android.util.Log;
@@ -39,7 +38,7 @@
* 4. Verify {@link GnssNavigationMessage}s (all mandatory fields), the test will fail if any of the
* mandatory fields is not populated or in the expected range.
*/
-public class GnssNavigationMessageTest extends AndroidTestCase {
+public class GnssNavigationMessageTest extends GnssTestCase {
private static final String TAG = "GpsNavMsgTest";
private TestLocationManager mTestLocationManager;
diff --git a/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java
index d69fc01..4544c40 100644
--- a/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java
@@ -17,9 +17,8 @@
package android.location.cts;
import android.location.GnssStatusCallback;
-import android.test.AndroidTestCase;
-public class GnssStatusCallbackTest extends AndroidTestCase {
+public class GnssStatusCallbackTest extends GnssTestCase {
private static class MockCallback extends GnssStatusCallback {
}
diff --git a/tests/tests/location/src/android/location/cts/GnssTestCase.java b/tests/tests/location/src/android/location/cts/GnssTestCase.java
new file mode 100644
index 0000000..35d8226
--- /dev/null
+++ b/tests/tests/location/src/android/location/cts/GnssTestCase.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.location.cts;
+
+import android.test.AndroidTestCase;
+
+/**
+ * Base Test Case class for all Gnss Tests.
+ */
+public abstract class GnssTestCase extends AndroidTestCase {
+ protected GnssTestCase() {}
+}
\ No newline at end of file
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index 5e97cc2..9064ade 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -36,6 +36,13 @@
android:label="AudioManagerStub"/>
<activity android:name="android.media.cts.AudioManagerStubHelper"
android:label="AudioManagerStubHelper"/>
+ <activity android:name="android.media.cts.DecodeAccuracyTestActivity"
+ android:label="DecodeAccuracyTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
<activity android:name="android.media.cts.MediaStubActivity"
android:label="MediaStubActivity"
android:screenOrientation="nosensor"
diff --git a/tests/tests/media/assets/360pvp9decodertest.webm b/tests/tests/media/assets/360pvp9decodertest.webm
new file mode 100644
index 0000000..e35e7a8
--- /dev/null
+++ b/tests/tests/media/assets/360pvp9decodertest.webm
Binary files differ
diff --git a/tests/tests/media/assets/480ph264decodertest.mp4 b/tests/tests/media/assets/480ph264decodertest.mp4
new file mode 100644
index 0000000..9b7e894
--- /dev/null
+++ b/tests/tests/media/assets/480ph264decodertest.mp4
Binary files differ
diff --git a/tests/tests/media/res/layout/test_runner_activity.xml b/tests/tests/media/res/layout/test_runner_activity.xml
new file mode 100644
index 0000000..8cc88ea
--- /dev/null
+++ b/tests/tests/media/res/layout/test_runner_activity.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+ <HorizontalScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="250dp">
+ <ScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent">
+ <RelativeLayout
+ android:id="@+id/attach_view"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"/>
+ </ScrollView>
+ </HorizontalScrollView>
+ <ListView
+ android:id="@+id/test_case_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/tests/tests/media/res/raw/h264decodertestgolden.png b/tests/tests/media/res/raw/h264decodertestgolden.png
new file mode 100644
index 0000000..bfaea26
--- /dev/null
+++ b/tests/tests/media/res/raw/h264decodertestgolden.png
Binary files differ
diff --git a/tests/tests/media/res/raw/sinesweepopus.mkv b/tests/tests/media/res/raw/sinesweepopus.mkv
new file mode 100644
index 0000000..230dd36
--- /dev/null
+++ b/tests/tests/media/res/raw/sinesweepopus.mkv
Binary files differ
diff --git a/tests/tests/media/res/raw/sinesweepvorbis.mkv b/tests/tests/media/res/raw/sinesweepvorbis.mkv
new file mode 100644
index 0000000..613ab71
--- /dev/null
+++ b/tests/tests/media/res/raw/sinesweepvorbis.mkv
Binary files differ
diff --git a/tests/tests/media/res/raw/vp9decodertestgolden.png b/tests/tests/media/res/raw/vp9decodertestgolden.png
new file mode 100644
index 0000000..cad6778
--- /dev/null
+++ b/tests/tests/media/res/raw/vp9decodertestgolden.png
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index c78f82a..d7ec5f1 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -81,8 +81,15 @@
}
public void testSoundEffects() throws Exception {
- // set relative setting
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ // set relative setting
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
Settings.System.putInt(mContext.getContentResolver(), SOUND_EFFECTS_ENABLED, 1);
// should hear sound after loadSoundEffects() called.
@@ -343,6 +350,9 @@
}
public void testSetRingerModePolicyAccess() throws Exception {
+ if (mUseFixedVolume || mIsTelevision) {
+ return;
+ }
try {
// Apps without policy access cannot change silent -> normal or silent -> vibrate.
Utils.toggleNotificationPolicyAccess(
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index e8239ff..a8fb8fc 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -162,7 +162,7 @@
// just call the callback once directly so it's marked as tested
final AudioManager.AudioRecordingCallback arc =
(AudioManager.AudioRecordingCallback) callback;
- arc.onRecordConfigChanged(new AudioRecordingConfiguration[0]);
+ arc.onRecordingConfigChanged(new AudioRecordingConfiguration[0]);
}
public void testParcel() throws Exception {
@@ -216,7 +216,7 @@
}
@Override
- public void onRecordConfigChanged(AudioRecordingConfiguration[] configs) {
+ public void onRecordingConfigChanged(AudioRecordingConfiguration[] configs) {
mCalled = true;
mParamMatch = verifyAudioConfig(mTestSource, mTestSession, mAudioRecord.getFormat(),
mAudioRecord.getRoutedDevice(), configs);
diff --git a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
index e1e5c93..9ad8de9 100644
--- a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
@@ -367,7 +367,6 @@
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
getActivity().getSurfaceHolder(),
mSessionId,
- initDataType,
mContext.getResources());
mMediaCodecPlayer.setAudioDataSource(audioUrl, null, audioEncrypted);
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
new file mode 100644
index 0000000..319df5a
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.cts.util.MediaUtils;
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.cts.util.TimeoutReq;
+
+@TargetApi(16)
+public class DecodeAccuracyTest extends DecodeAccuracyTestBase {
+
+ private static final String TAG = DecodeAccuracyTest.class.getSimpleName();
+ private static final String H264_VIDEO_FILE_NAME = "480ph264decodertest.mp4";
+ private static final String VP9_VIDEO_FILE_NAME = "360pvp9decodertest.webm";
+ private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90;
+ private static final int TESTCASE_WAITTIME_MIN = 1;
+ private static final int OFFSET = 10;
+
+ /* <------------- Tests Using H264 -------------> */
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testH264TextureViewVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new TextureViewFactory(),
+ new VideoFormat(H264_VIDEO_FILE_NAME));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testH264TextureViewLargerHeightVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new TextureViewFactory(),
+ getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testH264TextureViewLargerWidthVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new TextureViewFactory(),
+ getLargerWidthVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testH264GLViewVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new GLSurfaceViewFactory(),
+ new VideoFormat(H264_VIDEO_FILE_NAME));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testH264GLViewLargerHeightVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new GLSurfaceViewFactory(),
+ getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testH264GLViewLargerWidthVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new GLSurfaceViewFactory(),
+ getLargerWidthVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+ }
+
+ /* <------------- Tests Using VP9 -------------> */
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testVP9TextureViewVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new TextureViewFactory(),
+ new VideoFormat(VP9_VIDEO_FILE_NAME));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testVP9TextureViewLargerHeightVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new TextureViewFactory(),
+ getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testVP9TextureViewLargerWidthVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new TextureViewFactory(),
+ getLargerWidthVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testVP9GLViewVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new GLSurfaceViewFactory(),
+ new VideoFormat(VP9_VIDEO_FILE_NAME));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testVP9GLViewLargerHeightVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new GLSurfaceViewFactory(),
+ getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+ }
+
+ @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+ public void testVP9GLViewLargerWidthVideoDecode() throws Exception {
+ runDecodeAccuracyTest(
+ new GLSurfaceViewFactory(),
+ getLargerWidthVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+ }
+
+ private void runDecodeAccuracyTest(VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
+ checkNotNull(videoViewFactory);
+ checkNotNull(videoFormat);
+ if (!DisplayUtil.canPlay360p(getHelper().getContext())) {
+ MediaUtils.skipTest("Display does not support 360p.");
+ return;
+ }
+ if (!DisplayUtil.currentOrientationCanPlay360p(getHelper().getContext())) {
+ Log.w(TAG, "Current screen orientation does not support 360p.");
+ Log.i(TAG, "Rotate screen orientation and continue.");
+ getHelper().rotateOrientation();
+ }
+ View videoView = videoViewFactory.createView(getHelper().getContext());
+ // If view is intended and available to display.
+ if (videoView != null) {
+ getHelper().generateView(videoView);
+ }
+ videoViewFactory.waitForViewIsAvailable();
+
+ decodeVideo(videoFormat, videoViewFactory);
+ validateResult(videoFormat, videoViewFactory);
+
+ if (videoView != null) {
+ getHelper().cleanUpView(videoView);
+ }
+ videoViewFactory.release();
+ getHelper().unsetOrientation();
+ }
+
+ private void decodeVideo(VideoFormat videoFormat, VideoViewFactory videoViewFactory) {
+ final SimplePlayer player = new SimplePlayer(getHelper().getContext());
+ final SimplePlayer.PlayerResult playerResult = player.decodeVideoFrames(
+ videoViewFactory.getSurface(), videoFormat, 10);
+ assertTrue("Failed to configure video decoder.", playerResult.isConfigureSuccess());
+ assertTrue("Failed to start video decoder.", playerResult.isStartSuccess());
+ assertTrue("Failed to decode the video.", playerResult.isSuccess());
+ }
+
+ private void validateResult(VideoFormat videoFormat, VideoViewFactory videoViewFactory) {
+ final Bitmap result = getHelper().generateBitmapFromVideoViewSnapshot(
+ videoViewFactory.getVideoViewSnapshot());
+ final Bitmap golden;
+ final String mime = videoFormat.getMimeType();
+ if (mime.equals(MimeTypes.VIDEO_H264)) {
+ golden = getHelper().generateBitmapFromImageResourceId(R.raw.h264decodertestgolden);
+ } else if (mime.equals(MimeTypes.VIDEO_VP9)) {
+ golden = getHelper().generateBitmapFromImageResourceId(R.raw.vp9decodertestgolden);
+ } else {
+ fail("Unsupported MIME type " + mime);
+ return;
+ }
+ final BitmapCompare.Difference difference = BitmapCompare.computeDifference(golden, result);
+ assertTrue("Greatest pixel difference is "
+ + difference.greatestPixelDifference
+ + (difference.greatestPixelDifferenceCoordinates != null
+ ? " at (" + difference.greatestPixelDifferenceCoordinates.first + ", "
+ + difference.greatestPixelDifferenceCoordinates.second + ")" : "")
+ + " which is over the allowed difference " + ALLOWED_GREATEST_PIXEL_DIFFERENCE,
+ difference.greatestPixelDifference <= ALLOWED_GREATEST_PIXEL_DIFFERENCE);
+ }
+
+ private static VideoFormat getLargerHeightVideoFormat(VideoFormat videoFormat) {
+ return new VideoFormat(videoFormat) {
+ @Override
+ public int getHeight() {
+ return super.getHeight() + OFFSET;
+ }
+ @Override
+ public int getMaxHeight() {
+ return super.getHeight() * 2 + OFFSET;
+ }
+ @Override
+ public int getMaxWidth() {
+ return super.getWidth() * 2 + OFFSET;
+ }
+ };
+ }
+
+ private static VideoFormat getLargerWidthVideoFormat(VideoFormat videoFormat) {
+ return new VideoFormat(videoFormat) {
+ @Override
+ public int getWidth() {
+ return super.getWidth() + OFFSET;
+ }
+ @Override
+ public int getMaxHeight() {
+ return super.getHeight() * 2 + OFFSET;
+ }
+ @Override
+ public int getMaxWidth() {
+ return super.getWidth() * 2 + OFFSET;
+ }
+ };
+ }
+
+ private static final class DisplayUtil {
+
+ public static boolean canPlay360p(Context context) {
+ return displayMetricsHasMinPixelSize(context, 360);
+ }
+
+ public static boolean currentOrientationCanPlay360p(Context context) {
+ DisplayMetrics metrics = getDisplayMetrics(context);
+ return metrics.widthPixels >= 480 && metrics.heightPixels >= 360;
+ }
+
+ private static boolean displayMetricsHasMinPixelSize(Context context, int minPixelSize) {
+ return getDisplayMetricsMinPixelSize(context) >= minPixelSize;
+ }
+
+ private static int getDisplayMetricsMinPixelSize(Context context) {
+ DisplayMetrics metrics = getDisplayMetrics(context);
+ return Math.min(metrics.widthPixels, metrics.heightPixels);
+ }
+
+ private static DisplayMetrics getDisplayMetrics(Context context) {
+ checkNotNull(context);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay().getRealMetrics(metrics);
+ return metrics;
+ } else {
+ return context.getResources().getDisplayMetrics();
+ }
+ }
+
+ }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
new file mode 100644
index 0000000..da06844
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class DecodeAccuracyTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.test_runner_activity);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
new file mode 100644
index 0000000..8caf495
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.opengl.EGL14;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.concurrent.TimeUnit;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+@TargetApi(16)
+public class DecodeAccuracyTestBase
+ extends ActivityInstrumentationTestCase2<DecodeAccuracyTestActivity> {
+
+ protected Context mContext;
+ protected Resources mResources;
+ protected DecodeAccuracyTestActivity mActivity;
+ protected TestHelper testHelper;
+
+ public DecodeAccuracyTestBase() {
+ super(DecodeAccuracyTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ getInstrumentation().waitForIdleSync();
+ mContext = getInstrumentation().getTargetContext();
+ mResources = mContext.getResources();
+ testHelper = new TestHelper(mContext, mActivity);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mActivity = null;
+ super.tearDown();
+ }
+
+ protected TestHelper getHelper() {
+ return testHelper;
+ }
+
+ public static <T> T checkNotNull(T reference) {
+ assertNotNull(reference);
+ return reference;
+ }
+
+ public static class SimplePlayer {
+
+ public static final long DECODE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1) / 2;
+
+ private static final int NO_TRACK_INDEX = -3;
+ private static final long DEQUEUE_TIMEOUT_US = 20;
+ private static final String TAG = SimplePlayer.class.getSimpleName();
+
+ private final Context context;
+ private final MediaExtractor extractor;
+ private MediaCodec decoder;
+
+ public SimplePlayer(Context context) {
+ this(context, new MediaExtractor());
+ }
+
+ public SimplePlayer(Context context, MediaExtractor extractor) {
+ this.context = checkNotNull(context);
+ this.extractor = checkNotNull(extractor);
+ }
+
+ /*
+ * The function play the corresponding file for certain number of frames,
+ *
+ * @param surface is the surface view of decoder output.
+ * @param videoFormat is the format of the video to extract and decode.
+ * @param numOfTotalFrame is the number of Frame wish to play.
+ * @return a PlayerResult object indicating success or failure.
+ */
+ public PlayerResult decodeVideoFrames(
+ Surface surface, VideoFormat videoFormat, int numOfTotalFrames) {
+ PlayerResult playerResult;
+ if (prepare(surface, videoFormat)) {
+ if (startDecoder()) {
+ playerResult = decodeFramesAndDisplay(
+ surface, numOfTotalFrames, numOfTotalFrames * DECODE_TIMEOUT_MS);
+ } else {
+ playerResult = PlayerResult.failToStart();
+ }
+ } else {
+ playerResult = new PlayerResult();
+ }
+ release();
+ return new PlayerResult(playerResult);
+ }
+
+ public PlayerResult decodeVideoFrames(VideoFormat videoFormat, int numOfTotalFrames) {
+ return decodeVideoFrames(null, videoFormat, numOfTotalFrames);
+ }
+
+ /*
+ * The function set up the extractor and decoder with proper format.
+ * This must be called before decodeFramesAndDisplay.
+ */
+ private boolean prepare(Surface surface, VideoFormat videoFormat) {
+ if (!setExtractorDataSource(videoFormat)) {
+ return false;
+ }
+ int trackNum = getFirstVideoTrackIndex(extractor);
+ if (trackNum == NO_TRACK_INDEX) {
+ return false;
+ }
+ extractor.selectTrack(trackNum);
+ MediaFormat mediaFormat = extractor.getTrackFormat(trackNum);
+ configureFormat(mediaFormat, videoFormat);
+ return configureDecoder(surface, mediaFormat);
+ }
+
+ /* The function decode video frames and display in a surface. */
+ private PlayerResult decodeFramesAndDisplay(
+ Surface surface, int numOfTotalFrames, long timeOutMs) {
+ checkNotNull(decoder);
+ int numOfDecodedFrames = 0;
+ long decodeStart = 0;
+ boolean renderToSurface = surface != null ? true : false;
+ BufferInfo info = new BufferInfo();
+ ByteBuffer inputBuffer;
+ ByteBuffer[] inputBufferArray = decoder.getInputBuffers();
+ long loopStart = SystemClock.elapsedRealtime();
+
+ while (numOfDecodedFrames < numOfTotalFrames
+ && (SystemClock.elapsedRealtime() - loopStart < timeOutMs)) {
+ try {
+ int inputBufferIndex = decoder.dequeueInputBuffer(DEQUEUE_TIMEOUT_US);
+ if (inputBufferIndex >= 0) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ inputBuffer = inputBufferArray[inputBufferIndex];
+ } else {
+ inputBuffer = decoder.getInputBuffer(inputBufferIndex);
+ }
+ if (decodeStart == 0) {
+ decodeStart = SystemClock.elapsedRealtime();
+ }
+ int sampleSize = extractor.readSampleData(inputBuffer, 0);
+ if (sampleSize > 0) {
+ decoder.queueInputBuffer(
+ inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);
+ extractor.advance();
+ }
+ }
+ int decoderStatus = decoder.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT_US);
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ break;
+ }
+ if (decoderStatus >= 0 && info.size > 0) {
+ decoder.releaseOutputBuffer(decoderStatus, renderToSurface);
+ numOfDecodedFrames++;
+ }
+ } catch (IllegalStateException exception) {
+ Log.e(TAG, "IllegalStateException in decodeFramesAndDisplay " + exception);
+ break;
+ }
+ }
+ long totalTime = SystemClock.elapsedRealtime() - decodeStart;
+ return new PlayerResult(true, true, numOfTotalFrames == numOfDecodedFrames, totalTime);
+ }
+
+ private void release() {
+ decoderRelease();
+ extractorRelease();
+ }
+
+ private boolean setExtractorDataSource(VideoFormat videoFormat) {
+ try {
+ extractor.setDataSource(context, videoFormat.loadUri(context), null);
+ } catch (IOException exception) {
+ Log.e(TAG, "IOException in setDataSource", exception);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean configureDecoder(Surface surface, MediaFormat mediaFormat) {
+ try {
+ decoder = MediaCodec.createDecoderByType(
+ mediaFormat.getString(MediaFormat.KEY_MIME));
+ decoder.configure(mediaFormat, surface, null, 0);
+ } catch (Exception exception) {
+ if (exception instanceof IOException) {
+ Log.e(TAG, "IOException in createDecoderByType", exception);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+ && exception instanceof CodecException) {
+ Log.e(TAG, "CodecException in createDecoderByType", exception);
+ decoder.reset();
+ } else {
+ Log.e(TAG, "Unknown exception in createDecoderByType", exception);
+ }
+ decoderRelease();
+ return false;
+ }
+ return true;
+ }
+
+ private boolean startDecoder() {
+ try {
+ decoder.start();
+ } catch (Exception exception) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+ && exception instanceof CodecException) {
+ Log.e(TAG, "CodecException in startDecoder", exception);
+ decoder.reset();
+ } else if (exception instanceof IllegalStateException) {
+ Log.e(TAG, "IllegalStateException in startDecoder", exception);
+ } else {
+ Log.e(TAG, "Unknown exception in startDecoder", exception);
+ }
+ decoderRelease();
+ return false;
+ }
+ return true;
+ }
+
+ private void decoderRelease() {
+ if (decoder == null) {
+ return;
+ }
+ try {
+ decoder.stop();
+ } catch (IllegalStateException exception) {
+ // IllegalStateException happens when decoder fail to start.
+ Log.e(TAG, "IllegalStateException in decoder stop" + exception);
+ } finally {
+ try {
+ decoder.release();
+ } catch (IllegalStateException exception) {
+ Log.e(TAG, "IllegalStateException in decoder release" + exception);
+ }
+ }
+ decoder = null;
+ }
+
+ private void extractorRelease() {
+ if (extractor == null) {
+ return;
+ }
+ try {
+ extractor.release();
+ } catch (IllegalStateException exception) {
+ Log.e(TAG, "IllegalStateException in extractor release" + exception);
+ }
+ }
+
+ private static void configureFormat(MediaFormat mediaFormat, VideoFormat videoFormat) {
+ checkNotNull(mediaFormat);
+ checkNotNull(videoFormat);
+ videoFormat.setMimeType(mediaFormat.getString(MediaFormat.KEY_MIME));
+ videoFormat.setWidth(mediaFormat.getInteger(MediaFormat.KEY_WIDTH));
+ videoFormat.setHeight(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT));
+ mediaFormat.setInteger(MediaFormat.KEY_WIDTH, videoFormat.getWidth());
+ mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, videoFormat.getHeight());
+
+ if (videoFormat.getMaxWidth() != VideoFormat.UNSET
+ && videoFormat.getMaxHeight() != VideoFormat.UNSET) {
+ mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, videoFormat.getMaxWidth());
+ mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, videoFormat.getMaxHeight());
+ }
+ }
+
+ /*
+ * The function returns the first video track found.
+ *
+ * @param extractor is the media extractor instantiated with a video uri.
+ * @return the index of the first video track if found, NO_TRACK_INDEX otherwise.
+ */
+ private static int getFirstVideoTrackIndex(MediaExtractor extractor) {
+ for (int i = 0; i < extractor.getTrackCount(); i++) {
+ MediaFormat trackMediaFormat = extractor.getTrackFormat(i);
+ if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
+ return i;
+ }
+ }
+ Log.e(TAG, "couldn't get a video track");
+ return NO_TRACK_INDEX;
+ }
+
+ /* Stores the result from SimplePlayer. */
+ public static final class PlayerResult {
+
+ public static final int UNSET = -1;
+ private final boolean configureSuccess;
+ private final boolean startSuccess;
+ private final boolean decodeSuccess;
+ private final long totalTime;
+
+ public PlayerResult(
+ boolean configureSuccess, boolean startSuccess,
+ boolean decodeSuccess, long totalTime) {
+ this.configureSuccess = configureSuccess;
+ this.startSuccess = startSuccess;
+ this.decodeSuccess = decodeSuccess;
+ this.totalTime = totalTime;
+ }
+
+ public PlayerResult(PlayerResult playerResult) {
+ this(playerResult.configureSuccess, playerResult.startSuccess,
+ playerResult.decodeSuccess, playerResult.totalTime);
+ }
+
+ public PlayerResult() {
+ // Dummy PlayerResult.
+ this(false, false, false, UNSET);
+ }
+
+ public static PlayerResult failToStart() {
+ return new PlayerResult(true, false, false, UNSET);
+ }
+
+ public boolean isConfigureSuccess() {
+ return configureSuccess;
+ }
+
+ public boolean isStartSuccess() {
+ return startSuccess;
+ }
+
+ public boolean isDecodeSuccess() {
+ return decodeSuccess;
+ }
+
+ public boolean isSuccess() {
+ return isConfigureSuccess() && isStartSuccess()
+ && isDecodeSuccess() && getTotalTime() != UNSET;
+ }
+
+ public long getTotalTime() {
+ return totalTime;
+ }
+
+ public boolean isFailureForAll() {
+ return (!isConfigureSuccess() && !isStartSuccess()
+ && !isDecodeSuccess() && getTotalTime() == UNSET);
+ }
+ }
+
+ }
+
+ /* Utility class for collecting common test case functionality. */
+ class TestHelper {
+
+ private final Context context;
+ private final Handler handler;
+ private final Activity activity;
+
+ public TestHelper(Context context, Activity activity) {
+ this.context = checkNotNull(context);
+ this.handler = new Handler(Looper.getMainLooper());
+ this.activity = activity;
+ }
+
+ public Bitmap generateBitmapFromImageResourceId(int resourceId) {
+ return BitmapFactory.decodeStream(context.getResources().openRawResource(resourceId));
+ }
+
+ public Context getContext() {
+ return context;
+ }
+
+ public void rotateOrientation() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ final int orientation = context.getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ } else {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ }
+ }
+ });
+ }
+
+ public void unsetOrientation() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+ });
+ }
+
+ public void generateView(View view) {
+ RelativeLayout relativeLayout =
+ (RelativeLayout) activity.findViewById(R.id.attach_view);
+ ViewGenerator viewGenerator = new ViewGenerator(relativeLayout, view);
+ handler.post(viewGenerator);
+ }
+
+ public void cleanUpView(View view) {
+ ViewCleaner viewCleaner = new ViewCleaner(view);
+ handler.post(viewCleaner);
+ }
+
+ public synchronized Bitmap generateBitmapFromVideoViewSnapshot(VideoViewSnapshot snapshot) {
+ handler.post(snapshot);
+ try {
+ while (!snapshot.isBitmapReady()) {
+ Thread.sleep(100);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return snapshot.getBitmap();
+ }
+
+ private class ViewGenerator implements Runnable {
+
+ private final View view;
+ private final RelativeLayout relativeLayout;
+
+ public ViewGenerator(RelativeLayout relativeLayout, View view) {
+ this.view = checkNotNull(view);
+ this.relativeLayout = checkNotNull(relativeLayout);
+ }
+
+ @Override
+ public void run() {
+ if (view.getParent() != null) {
+ ((ViewGroup) view.getParent()).removeView(view);
+ }
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+ VideoViewFactory.VIEW_WIDTH, VideoViewFactory.VIEW_HEIGHT);
+ view.setLayoutParams(params);
+ relativeLayout.addView(view);
+ }
+
+ }
+
+ private class ViewCleaner implements Runnable {
+
+ private final View view;
+
+ public ViewCleaner(View view) {
+ this.view = checkNotNull(view);
+ }
+
+ @Override
+ public void run() {
+ if (view.getParent() != null) {
+ ((ViewGroup) view.getParent()).removeView(view);
+ }
+ }
+
+ }
+
+ }
+
+}
+
+/* Factory for manipulating a {@link View}. */
+abstract class VideoViewFactory {
+
+ public final long VIEW_AVAILABLE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
+ public static final int VIEW_WIDTH = 480;
+ public static final int VIEW_HEIGHT = 360;
+
+ public VideoViewFactory() {}
+
+ public abstract void release();
+
+ public abstract String getName();
+
+ public abstract View createView(Context context);
+
+ public abstract void waitForViewIsAvailable();
+
+ public abstract Surface getSurface();
+
+ public abstract VideoViewSnapshot getVideoViewSnapshot();
+
+}
+
+/* Factory for building a {@link TextureView}. */
+@TargetApi(16)
+class TextureViewFactory extends VideoViewFactory implements TextureView.SurfaceTextureListener {
+
+ private final String TAG = TextureViewFactory.class.getSimpleName();
+ private final Object syncToken = new Object();
+ private TextureView textureView;
+
+ public TextureViewFactory() {}
+
+ @Override
+ public TextureView createView(Context context) {
+ textureView = DecodeAccuracyTestBase.checkNotNull(new TextureView(context));
+ textureView.setSurfaceTextureListener(this);
+ return textureView;
+ }
+
+ @Override
+ public void release() {
+ textureView = null;
+ }
+
+ @Override
+ public String getName() {
+ return "TextureView";
+ }
+
+ @Override
+ public Surface getSurface() {
+ return new Surface(textureView.getSurfaceTexture());
+ }
+
+ @Override
+ public TextureViewSnapshot getVideoViewSnapshot() {
+ return new TextureViewSnapshot(textureView);
+ }
+
+ @Override
+ public void waitForViewIsAvailable() {
+ while (!textureView.isAvailable()) {
+ synchronized (syncToken) {
+ try {
+ syncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
+ } catch (InterruptedException exception) {
+ Log.e(TAG, "InterruptedException in waitForViewIsAvailable", exception);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
+ synchronized (syncToken) {
+ syncToken.notify();
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(
+ SurfaceTexture surfaceTexture, int width, int height) {}
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
+
+}
+
+/**
+ * Factory for building EGL and GLES that could render to GLSurfaceView.
+ * {@link GLSurfaceView} {@link EGL10} {@link GLES20}.
+ */
+@TargetApi(16)
+class GLSurfaceViewFactory extends VideoViewFactory {
+
+ private final String TAG = GLSurfaceViewFactory.class.getSimpleName();
+ private final Object surfaceSyncToken = new Object();
+ private final Object snapshotSyncToken = new Object();
+
+ private GLSurfaceViewThread glSurfaceViewThread;
+ private boolean snapshotIsReady = false;
+
+ public GLSurfaceViewFactory() {}
+
+ @Override
+ public void release() {
+ glSurfaceViewThread.release();
+ glSurfaceViewThread = null;
+ }
+
+ @Override
+ public String getName() {
+ return "GLSurfaceView";
+ }
+
+ @Override
+ public View createView(Context context) {
+ // Do all GL rendering in the GL thread.
+ glSurfaceViewThread = new GLSurfaceViewThread();
+ glSurfaceViewThread.start();
+ // No necessary view to display, return null.
+ return null;
+ }
+
+ @Override
+ public void waitForViewIsAvailable() {
+ while (glSurfaceViewThread.getSurface() == null) {
+ synchronized (surfaceSyncToken) {
+ try {
+ surfaceSyncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
+ } catch (InterruptedException exception) {
+ Log.e(TAG, "InterruptedException in waitForViewIsAvailable", exception);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Surface getSurface() {
+ return glSurfaceViewThread.getSurface();
+ }
+
+ @Override
+ public VideoViewSnapshot getVideoViewSnapshot() {
+ while (!snapshotIsReady) {
+ synchronized (snapshotSyncToken) {
+ try {
+ snapshotSyncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
+ } catch (InterruptedException exception) {
+ Log.e(TAG, "InterruptedException in getVideoViewSnapshot", exception);
+ }
+ }
+ }
+ return new GLSurfaceViewSnapshot(
+ glSurfaceViewThread.getByteBuffer(), VIEW_WIDTH, VIEW_HEIGHT);
+ }
+
+ /* Does all GL operations. */
+ private class GLSurfaceViewThread extends Thread
+ implements SurfaceTexture.OnFrameAvailableListener {
+
+ private static final int FLOAT_SIZE_BYTES = 4;
+ private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+ private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+ private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+ private FloatBuffer triangleVertices;
+
+ private final float[] triangleVerticesData = {
+ // X, Y, Z, U, V
+ -1.0f, -1.0f, 0, 0.f, 0.f,
+ 1.0f, -1.0f, 0, 1.f, 0.f,
+ -1.0f, 1.0f, 0, 0.f, 1.f,
+ 1.0f, 1.0f, 0, 1.f, 1.f,
+ };
+
+ private static final String VERTEX_SHADER =
+ "attribute vec4 aPosition;\n"
+ + "attribute vec4 aTextureCoord;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ + " gl_Position = aPosition;\n"
+ + " vTextureCoord = aTextureCoord.xy;\n"
+ + "}\n";
+
+ private static final String FRAGMENT_SHADER =
+ "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n" // highp here doesn't seem to matter
+ + "varying vec2 vTextureCoord;\n"
+ + "uniform samplerExternalOES sTexture;\n"
+ + "void main() {\n"
+ + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n"
+ + "}\n";
+
+ private int glProgram;
+ private int textureID = -1;
+ private int aPositionHandle;
+ private int aTextureHandle;
+ private EGLDisplay eglDisplay = null;
+ private EGLContext eglContext = null;
+ private EGLSurface eglSurface = null;
+ private EGL10 egl10;
+ private Surface surface = null;
+ private SurfaceTexture surfaceTexture;
+ private ByteBuffer byteBuffer;
+
+ public GLSurfaceViewThread() {}
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ triangleVertices = ByteBuffer
+ .allocateDirect(triangleVerticesData.length * FLOAT_SIZE_BYTES)
+ .order(ByteOrder.nativeOrder()).asFloatBuffer();
+ triangleVertices.put(triangleVerticesData).position(0);
+
+ eglSetup();
+ makeCurrent();
+ eglSurfaceCreated();
+
+ surfaceTexture = new SurfaceTexture(getTextureId());
+ surfaceTexture.setOnFrameAvailableListener(this);
+ surface = new Surface(surfaceTexture);
+ synchronized (surfaceSyncToken) {
+ surfaceSyncToken.notify();
+ }
+
+ // Store pixels from surface
+ byteBuffer = ByteBuffer.allocateDirect(VIEW_WIDTH * VIEW_HEIGHT * 4);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ Looper.loop();
+ }
+
+ @Override
+ public void onFrameAvailable(SurfaceTexture st) {
+ checkGlError("before updateTexImage");
+ surfaceTexture.updateTexImage();
+ drawFrame();
+ saveFrame();
+ snapshotIsReady = true;
+ synchronized(snapshotSyncToken) {
+ snapshotSyncToken.notify();
+ }
+ }
+
+ /* Prepares EGL to use GLES 2.0 context and a surface that supports pbuffer. */
+ public void eglSetup() {
+ egl10 = (EGL10) EGLContext.getEGL();
+ eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("unable to get egl10 display");
+ }
+ int[] version = new int[2];
+ if (!egl10.eglInitialize(eglDisplay, version)) {
+ eglDisplay = null;
+ throw new RuntimeException("unable to initialize egl10");
+ }
+ // Configure EGL for pbuffer and OpenGL ES 2.0, 24-bit RGB.
+ int[] configAttribs = {
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,
+ EGL10.EGL_NONE
+ };
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] numConfigs = new int[1];
+ if (!egl10.eglChooseConfig(
+ eglDisplay, configAttribs, configs, configs.length, numConfigs)) {
+ throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
+ }
+ // Configure EGL context for OpenGL ES 2.0.
+ int[] contextAttribs = {
+ EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL10.EGL_NONE
+ };
+ eglContext = egl10.eglCreateContext(
+ eglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, contextAttribs);
+ checkEglError("eglCreateContext");
+ if (eglContext == null) {
+ throw new RuntimeException("null context");
+ }
+ // Create a pbuffer surface.
+ int[] surfaceAttribs = {
+ EGL10.EGL_WIDTH, VIEW_WIDTH,
+ EGL10.EGL_HEIGHT, VIEW_HEIGHT,
+ EGL10.EGL_NONE
+ };
+ eglSurface = egl10.eglCreatePbufferSurface(eglDisplay, configs[0], surfaceAttribs);
+ checkEglError("eglCreatePbufferSurface");
+ if (eglSurface == null) {
+ throw new RuntimeException("surface was null");
+ }
+ }
+
+ public void release() {
+ if (eglDisplay != EGL10.EGL_NO_DISPLAY) {
+ egl10.eglMakeCurrent(eglDisplay,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ egl10.eglDestroySurface(eglDisplay, eglSurface);
+ egl10.eglDestroyContext(eglDisplay, eglContext);
+ egl10.eglTerminate(eglDisplay);
+ }
+ eglDisplay = EGL10.EGL_NO_DISPLAY;
+ eglContext = EGL10.EGL_NO_CONTEXT;
+ eglSurface = EGL10.EGL_NO_SURFACE;
+ surface.release();
+ surfaceTexture.release();
+ }
+
+ /* Makes our EGL context and surface current. */
+ public void makeCurrent() {
+ if (!egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed");
+ }
+ checkEglError("eglMakeCurrent");
+ }
+
+ /* Call this after the EGL Surface is created and made current. */
+ public void eglSurfaceCreated() {
+ glProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
+ if (glProgram == 0) {
+ throw new RuntimeException("failed creating program");
+ }
+ aPositionHandle = GLES20.glGetAttribLocation(glProgram, "aPosition");
+ checkLocation(aPositionHandle, "aPosition");
+ aTextureHandle = GLES20.glGetAttribLocation(glProgram, "aTextureCoord");
+ checkLocation(aTextureHandle, "aTextureCoord");
+
+ int[] textures = new int[1];
+ GLES20.glGenTextures(1, textures, 0);
+ checkGlError("glGenTextures");
+ textureID = textures[0];
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID);
+ checkGlError("glBindTexture");
+
+ GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_LINEAR);
+ GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+ GLES20.GL_LINEAR);
+ GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
+ GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
+ GLES20.GL_CLAMP_TO_EDGE);
+ checkGlError("glTexParameter");
+ }
+
+ public void drawFrame() {
+ GLES20.glUseProgram(glProgram);
+ checkGlError("glUseProgram");
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ checkGlError("glActiveTexture");
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID);
+ checkGlError("glBindTexture");
+
+ triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+ GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+ checkGlError("glVertexAttribPointer aPositionHandle");
+ GLES20.glEnableVertexAttribArray(aPositionHandle);
+ checkGlError("glEnableVertexAttribArray aPositionHandle");
+
+ triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+ GLES20.glVertexAttribPointer(aTextureHandle, 2, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+ checkGlError("glVertexAttribPointer aTextureHandle");
+ GLES20.glEnableVertexAttribArray(aTextureHandle);
+ checkGlError("glEnableVertexAttribArray aTextureHandle");
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+ checkGlError("glDrawArrays");
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+ }
+
+ /* Reads the pixels to a ByteBuffer. */
+ public void saveFrame() {
+ byteBuffer.clear();
+ GLES20.glReadPixels(0, 0, VIEW_WIDTH, VIEW_HEIGHT, GLES20.GL_RGBA,
+ GLES20.GL_UNSIGNED_BYTE, byteBuffer);
+ }
+
+ public int getTextureId() {
+ return textureID;
+ }
+
+ public Surface getSurface() {
+ return surface;
+ }
+
+ public ByteBuffer getByteBuffer() {
+ return byteBuffer;
+ }
+
+ private int loadShader(int shaderType, String source) {
+ int shader = GLES20.glCreateShader(shaderType);
+ checkGlError("glCreateShader type=" + shaderType);
+ GLES20.glShaderSource(shader, source);
+ GLES20.glCompileShader(shader);
+ int[] compiled = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+
+ if (compiled[0] == 0) {
+ Log.e(TAG, "Could not compile shader " + shaderType + ":");
+ Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader));
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ return shader;
+ }
+
+ private int createProgram(String vertexSource, String fragmentSource) {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+ if (vertexShader == 0) {
+ return 0;
+ }
+ int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+ if (pixelShader == 0) {
+ return 0;
+ }
+ int program = GLES20.glCreateProgram();
+ if (program == 0) {
+ Log.e(TAG, "Could not create program");
+ }
+ GLES20.glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ GLES20.glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ GLES20.glLinkProgram(program);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ return program;
+ }
+
+ private void checkEglError(String msg) {
+ int error;
+ if ((error = egl10.eglGetError()) != EGL10.EGL_SUCCESS) {
+ throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
+ }
+ }
+
+ public void checkGlError(String op) {
+ int error;
+ if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+ Log.e(TAG, op + ": glError " + error);
+ throw new RuntimeException(op + ": glError " + error);
+ }
+ }
+
+ public void checkLocation(int location, String label) {
+ if (location < 0) {
+ throw new RuntimeException("Unable to locate '" + label + "' in program");
+ }
+ }
+ }
+
+}
+
+/* Definition of a VideoViewSnapshot and a runnable to get a bitmap from a view. */
+abstract class VideoViewSnapshot implements Runnable {
+
+ public abstract Bitmap getBitmap();
+
+ public abstract boolean isBitmapReady();
+
+}
+
+/* Runnable to get a bitmap from a texture view on the UI thread via a handler. */
+class TextureViewSnapshot extends VideoViewSnapshot {
+
+ private final TextureView tv;
+ private Bitmap bitmap = null;
+
+ public TextureViewSnapshot(TextureView tv) {
+ this.tv = DecodeAccuracyTestBase.checkNotNull(tv);
+ }
+
+ @Override
+ public synchronized void run() {
+ bitmap = tv.getBitmap();
+ }
+
+ @Override
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+
+ @Override
+ public boolean isBitmapReady() {
+ return bitmap != null;
+ }
+
+}
+
+/**
+ * Runnable to get a bitmap from a GLSurfaceView on the UI thread via a handler.
+ * Note, because of how the bitmap is captured in GLSurfaceView,
+ * this method does not have to be a runnable.
+ */
+class GLSurfaceViewSnapshot extends VideoViewSnapshot {
+
+ private Bitmap bitmap = null;
+ private ByteBuffer byteBuffer;
+ private final int width;
+ private final int height;
+ private boolean bitmapIsReady = false;
+
+ public GLSurfaceViewSnapshot(ByteBuffer byteBuffer, int width, int height) {
+ this.byteBuffer = DecodeAccuracyTestBase.checkNotNull(byteBuffer);
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public synchronized void run() {
+ bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ byteBuffer.rewind();
+ bitmap.copyPixelsFromBuffer(byteBuffer);
+ bitmapIsReady = true;
+ }
+
+ @Override
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+
+ @Override
+ public boolean isBitmapReady() {
+ return bitmapIsReady;
+ }
+
+}
+
+/* Stores information of a video. */
+class VideoFormat {
+
+ public static final int UNSET = -1;
+ public static final String MIMETYPE_UNSET = "UNSET";
+ public static final String MIMETYPE_KEY = "mimeType";
+ public static final String WIDTH_KEY = "width";
+ public static final String HEIGHT_KEY = "height";
+ public static final String FRAMERATE_KEY = "frameRate";
+
+ private final String filename;
+ private Uri uri;
+ private String mimeType = MIMETYPE_UNSET;
+ private int width = UNSET;
+ private int height = UNSET;
+ private int maxWidth = UNSET;
+ private int maxHeight = UNSET;
+
+ public VideoFormat(String filename, Uri uri) {
+ this.filename = filename;
+ this.uri = uri;
+ }
+
+ public VideoFormat(String filename) {
+ this(filename, null);
+ }
+
+ public VideoFormat(VideoFormat videoFormat) {
+ this(videoFormat.filename, videoFormat.uri);
+ }
+
+ public Uri loadUri(Context context) {
+ uri = createCacheFile(context);
+ return uri;
+ }
+
+ public Uri getUri() {
+ return uri;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setMimeType(String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public void setMaxWidth(int maxWidth) {
+ this.maxWidth = maxWidth;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getMaxWidth() {
+ return maxWidth;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void setMaxHeight(int maxHeight) {
+ this.maxHeight = maxHeight;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getMaxHeight() {
+ return maxHeight;
+ }
+
+ private Uri createCacheFile(Context context) {
+ try {
+ File cacheFile = new File(context.getCacheDir(), filename);
+ if (cacheFile.createNewFile() == false) {
+ cacheFile.delete();
+ cacheFile.createNewFile();
+ }
+ InputStream inputStream = context.getAssets().open(filename);
+ FileOutputStream fileOutputStream = new FileOutputStream(cacheFile);
+ final int bufferSize = 1024 * 512;
+ byte[] buffer = new byte[bufferSize];
+
+ while (inputStream.read(buffer) != -1) {
+ fileOutputStream.write(buffer, 0, bufferSize);
+ }
+ fileOutputStream.close();
+ inputStream.close();
+ return Uri.fromFile(cacheFile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+}
+
+/**
+ * Compares bitmaps to determine if they are similar.
+ *
+ * <p>To determine greatest pixel difference we transform each pixel into the
+ * CIE L*a*b* color space. The euclidean distance formula is used to determine pixel differences.
+ */
+class BitmapCompare {
+
+ private static final int RED = 0;
+ private static final int GREEN = 1;
+ private static final int BLUE = 2;
+ private static final int X = 0;
+ private static final int Y = 1;
+ private static final int Z = 2;
+
+ private static SparseArray<double[]> pixelTransformCache = new SparseArray<>();
+
+ private BitmapCompare() {}
+
+ /**
+ * Produces greatest pixel between two bitmaps. Used to determine bitmap similarity.
+ *
+ * @param bitmap1 A bitmap to compare to bitmap2.
+ * @param bitmap2 A bitmap to compare to bitmap1.
+ * @return A {@link Difference} with an integer describing the greatest pixel difference,
+ * using {@link Integer#MAX_VALUE} for completely different bitmaps, and an optional
+ * {@link Pair<Integer, Integer>} of the (col, row) pixel coordinate
+ * where it was first found.
+ */
+ @TargetApi(12)
+ public static Difference computeDifference(Bitmap bitmap1, Bitmap bitmap2) {
+ if ((bitmap1 == null || bitmap2 == null) && bitmap1 != bitmap2) {
+ return new Difference(Integer.MAX_VALUE);
+ }
+ if (bitmap1 == bitmap2 || bitmap1.sameAs(bitmap2)) {
+ return new Difference(0);
+ }
+ if (bitmap1.getHeight() != bitmap2.getHeight() || bitmap1.getWidth() != bitmap2.getWidth()) {
+ return new Difference(Integer.MAX_VALUE);
+ }
+ // Convert all pixels to CIE L*a*b* color space so we can do a direct color comparison using
+ // euclidean distance formula.
+ final double[][] pixels1 = convertRgbToCieLab(bitmap1);
+ final double[][] pixels2 = convertRgbToCieLab(bitmap2);
+ int greatestDifference = 0;
+ int greatestDifferenceIndex = -1;
+ for (int i = 0; i < pixels1.length; i++) {
+ final int difference = euclideanDistance(pixels1[i], pixels2[i]);
+ if (difference > greatestDifference) {
+ greatestDifference = difference;
+ greatestDifferenceIndex = i;
+ }
+ }
+ return new Difference(greatestDifference, Pair.create(
+ greatestDifferenceIndex % bitmap1.getWidth(),
+ greatestDifferenceIndex / bitmap1.getHeight()));
+ }
+
+ private static double[][] convertRgbToCieLab(Bitmap bitmap) {
+ final double[][] result = new double[bitmap.getHeight() * bitmap.getWidth()][3];
+ final int pixels[] = new int[bitmap.getHeight() * bitmap.getWidth()];
+ bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+ for (int i = 0; i < pixels.length; i++) {
+ final double[] transformedColor = pixelTransformCache.get(pixels[i]);
+ if (transformedColor != null) {
+ result[i] = transformedColor;
+ } else {
+ result[i] = convertXyzToCieLab(convertRgbToXyz(pixels[i]));
+ pixelTransformCache.put(pixels[i], result[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Conversion from RGB to XYZ based algorithm as defined by:
+ * http://www.easyrgb.com/index.php?X=MATH&H=02#text2
+ *
+ * <p><pre>{@code
+ * var_R = ( R / 255 ) //R from 0 to 255
+ * var_G = ( G / 255 ) //G from 0 to 255
+ * var_B = ( B / 255 ) //B from 0 to 255
+ *
+ * if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
+ * else var_R = var_R / 12.92
+ * if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
+ * else var_G = var_G / 12.92
+ * if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
+ * else var_B = var_B / 12.92
+ *
+ * var_R = var_R * 100
+ * var_G = var_G * 100
+ * var_B = var_B * 100
+ *
+ * // Observer. = 2°, Illuminant = D65
+ * X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
+ * Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
+ * Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505
+ * }</pre>
+ *
+ * @param rgbColor A packed int made up of 4 bytes: alpha, red, green, blue.
+ * @return An array of doubles where each value is a component of the XYZ color space.
+ */
+ private static double[] convertRgbToXyz(int rgbColor) {
+ final double[] comp = {Color.red(rgbColor), Color.green(rgbColor), Color.blue(rgbColor)};
+
+ for (int i = 0; i < comp.length; i++) {
+ comp[i] /= 255.0;
+ if (comp[i] > 0.04045) {
+ comp[i] = Math.pow((comp[i] + 0.055) / 1.055, 2.4);
+ } else {
+ comp[i] /= 12.92;
+ }
+ comp[i] *= 100;
+ }
+ final double x = (comp[RED] * 0.4124) + (comp[GREEN] * 0.3576) + (comp[BLUE] * 0.1805);
+ final double y = (comp[RED] * 0.2126) + (comp[GREEN] * 0.7152) + (comp[BLUE] * 0.0722);
+ final double z = (comp[RED] * 0.0193) + (comp[GREEN] * 0.1192) + (comp[BLUE] * 0.9505);
+ return new double[] {x, y, z};
+ }
+
+ /**
+ * Conversion from XYZ to CIE-L*a*b* based algorithm as defined by:
+ * http://www.easyrgb.com/index.php?X=MATH&H=07#text7
+ *
+ * <p><pre>
+ * {@code
+ * var_X = X / ref_X //ref_X = 95.047 Observer= 2°, Illuminant= D65
+ * var_Y = Y / ref_Y //ref_Y = 100.000
+ * var_Z = Z / ref_Z //ref_Z = 108.883
+ *
+ * if ( var_X > 0.008856 ) var_X = var_X ^ ( 1/3 )
+ * else var_X = ( 7.787 * var_X ) + ( 16 / 116 )
+ * if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
+ * else var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
+ * if ( var_Z > 0.008856 ) var_Z = var_Z ^ ( 1/3 )
+ * else var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )
+ *
+ * CIE-L* = ( 116 * var_Y ) - 16
+ * CIE-a* = 500 * ( var_X - var_Y )
+ * CIE-b* = 200 * ( var_Y - var_Z )
+ * }
+ * </pre>
+ *
+ * @param comp An array of doubles where each value is a component of the XYZ color space.
+ * @return An array of doubles where each value is a component of the CIE-L*a*b* color space.
+ */
+ private static double[] convertXyzToCieLab(double[] comp) {
+ comp[X] /= 95.047;
+ comp[Y] /= 100.0;
+ comp[Z] /= 108.883;
+
+ for (int i = 0; i < comp.length; i++) {
+ if (comp[i] > 0.008856) {
+ comp[i] = Math.pow(comp[i], (1.0 / 3.0));
+ } else {
+ comp[i] = (7.787 * comp[i]) + (16.0 / 116.0);
+ }
+ }
+ final double l = (116 * comp[Y]) - 16;
+ final double a = 500 * (comp[X] - comp[Y]);
+ final double b = 200 * (comp[Y] - comp[Z]);
+ return new double[] {l, a, b};
+ }
+
+ private static int euclideanDistance(double[] p1, double[] p2) {
+ if (p1.length != p2.length) {
+ return Integer.MAX_VALUE;
+ }
+ double result = 0;
+ for (int i = 0; i < p1.length; i++) {
+ result += Math.pow(p1[i] - p2[i], 2);
+ }
+ return (int) Math.round(Math.sqrt(result));
+ }
+
+ /* Describes the difference between two {@link Bitmap} instances. */
+ public static final class Difference {
+
+ public final int greatestPixelDifference;
+ public final Pair<Integer, Integer> greatestPixelDifferenceCoordinates;
+
+ private Difference(int greatestPixelDifference) {
+ this(greatestPixelDifference, null);
+ }
+
+ private Difference(
+ int greatestPixelDifference,
+ Pair<Integer, Integer> greatestPixelDifferenceCoordinates) {
+ this.greatestPixelDifference = greatestPixelDifference;
+ this.greatestPixelDifferenceCoordinates = greatestPixelDifferenceCoordinates;
+ }
+ }
+
+}
+
+/* Wrapper for MIME types. */
+final class MimeTypes {
+
+ private MimeTypes() {}
+
+ public static final String VIDEO_VP9 = "video/x-vnd.on2.vp9";
+ public static final String VIDEO_H264 = "video/avc";
+
+ public static boolean isVideo(String mimeType) {
+ return mimeType.startsWith("video");
+ }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index f6c1a0c..f4e259c 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -176,6 +176,14 @@
testTimeStampOrdering(R.raw.sinesweeptsaac);
}
+ public void testDecodeVorbis() throws Exception {
+ testTimeStampOrdering(R.raw.sinesweepvorbis);
+ }
+
+ public void testDecodeOpus() throws Exception {
+ testTimeStampOrdering(R.raw.sinesweepopus);
+ }
+
public void testDecode51M4a() throws Exception {
decodeToMemory(R.raw.sinesweep51m4a, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, null);
}
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index fc4a42a..dff6b1c 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -57,7 +57,7 @@
private static final String[] EXIF_TAGS = {
ExifInterface.TAG_MAKE,
ExifInterface.TAG_MODEL,
- ExifInterface.TAG_APERTURE,
+ ExifInterface.TAG_F_NUMBER,
ExifInterface.TAG_DATETIME,
ExifInterface.TAG_EXPOSURE_TIME,
ExifInterface.TAG_FLASH,
@@ -73,7 +73,7 @@
ExifInterface.TAG_GPS_TIMESTAMP,
ExifInterface.TAG_IMAGE_LENGTH,
ExifInterface.TAG_IMAGE_WIDTH,
- ExifInterface.TAG_ISO,
+ ExifInterface.TAG_ISO_SPEED_RATINGS,
ExifInterface.TAG_ORIENTATION,
ExifInterface.TAG_WHITE_BALANCE
};
@@ -295,7 +295,7 @@
// Checks values.
assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
- assertFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
+ assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
@@ -315,7 +315,7 @@
assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
- assertStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
+ assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
}
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 3e8458b..d9e6816 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -47,7 +47,7 @@
}
};
- private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
+ private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
new MediaBrowser.SubscriptionCallback() {
@Override
public void onChildrenLoaded(String parentId, List<MediaItem> children) {
@@ -56,10 +56,18 @@
mWaitLock.notify();
}
}
+
+ @Override
+ public void onChildrenLoaded(String parentId, List<MediaItem> children,
+ Bundle options) {
+ synchronized (mWaitLock) {
+ mOnChildrenLoadedWithOptions = true;
+ mWaitLock.notify();
+ }
+ }
};
- private final MediaBrowser.ItemCallback mItemCallback =
- new MediaBrowser.ItemCallback() {
+ private final MediaBrowser.ItemCallback mItemCallback = new MediaBrowser.ItemCallback() {
@Override
public void onItemLoaded(MediaItem item) {
synchronized (mWaitLock) {
@@ -72,6 +80,7 @@
private MediaBrowser mMediaBrowser;
private StubMediaBrowserService mMediaBrowserService;
private boolean mOnChildrenLoaded;
+ private boolean mOnChildrenLoadedWithOptions;
private boolean mOnItemLoaded;
@Override
@@ -108,6 +117,26 @@
}
}
+ public void testNotifyChildrenChangedWithPagination() throws Exception {
+ synchronized (mWaitLock) {
+ final int pageSize = 5;
+ final int page = 2;
+ Bundle options = new Bundle();
+ options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
+ options.putInt(MediaBrowser.EXTRA_PAGE, page);
+
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
+ mSubscriptionCallback);
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(mOnChildrenLoadedWithOptions);
+
+ mOnChildrenLoadedWithOptions = false;
+ mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(mOnChildrenLoadedWithOptions);
+ }
+ }
+
public void testDelayedNotifyChildrenChanged() throws Exception {
synchronized (mWaitLock) {
mOnChildrenLoaded = false;
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index 399a4e6..23f464e 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -122,11 +122,10 @@
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
final int pageSize = 3;
- final int lastPage = (StubMediaBrowserService.MEDIA_ID_CHILDREN.length + pageSize - 1)
- / pageSize;
+ final int lastPage = (StubMediaBrowserService.MEDIA_ID_CHILDREN.length - 1) / pageSize;
Bundle options = new Bundle();
options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
- for (int page = 1; page <= lastPage; ++page) {
+ for (int page = 0; page <= lastPage; ++page) {
resetCallbacks();
options.putInt(MediaBrowser.EXTRA_PAGE, page);
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
@@ -142,12 +141,12 @@
if (page != lastPage) {
assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
} else {
- assertEquals((StubMediaBrowserService.MEDIA_ID_CHILDREN.length + pageSize - 1)
- % pageSize + 1, mSubscriptionCallback.mLastChildMediaItems.size());
+ assertEquals((StubMediaBrowserService.MEDIA_ID_CHILDREN.length - 1) % pageSize + 1,
+ mSubscriptionCallback.mLastChildMediaItems.size());
}
// Check whether all the items in the current page are loaded.
for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
- assertEquals(StubMediaBrowserService.MEDIA_ID_CHILDREN[(page - 1) * pageSize + i],
+ assertEquals(StubMediaBrowserService.MEDIA_ID_CHILDREN[page * pageSize + i],
mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 129bfea..1d95463 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -18,6 +18,7 @@
import android.content.res.Resources;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
+import android.media.DrmInitData;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
@@ -77,7 +78,6 @@
private Thread mThread;
private Uri mAudioUri;
private Uri mVideoUri;
- private String mDrmInitDataType;
private Resources mResources;
private static final byte[] PSSH = hexStringToByteArray(
@@ -108,10 +108,9 @@
* Media player class to stream CENC content using MediaCodec class.
*/
public MediaCodecClearKeyPlayer(
- SurfaceHolder holder, byte[] sessionId, String initDataType, Resources resources) {
+ SurfaceHolder holder, byte[] sessionId, Resources resources) {
mSessionId = sessionId;
mSurfaceHolder = holder;
- mDrmInitDataType = initDataType;
mResources = resources;
mState = STATE_IDLE;
mThread = new Thread(new Runnable() {
@@ -152,41 +151,19 @@
return mMediaFormatWidth;
}
- public final Map<UUID, byte[]> getPsshInfo() {
- if (mVideoExtractor != null) {
- mPsshInitData = mVideoExtractor.getPsshInfo();
- }
- // TODO (edwinwong@)
- // Remove the if statement when we get content that has the clear key system id.
- if (mPsshInitData == null ||
- (mPsshInitData != null && !mPsshInitData.containsKey(CLEARKEY_SCHEME_UUID))) {
- mPsshInitData = new HashMap<UUID, byte[]>();
- mPsshInitData.put(CLEARKEY_SCHEME_UUID, PSSH);
- }
- return mPsshInitData;
- }
-
public final byte[] getDrmInitData() {
- if ("cenc".equals(mDrmInitDataType)) {
- return getPsshInfo().get(CLEARKEY_SCHEME_UUID);
- } else if ("webm".equals(mDrmInitDataType)) {
- for (MediaExtractor ex: new MediaExtractor[] {mVideoExtractor, mAudioExtractor}) {
- for (int i = ex.getTrackCount(); i-- > 0;) {
- MediaFormat format = ex.getTrackFormat(i);
- // TODO use public api if possible
- ByteBuffer cryptoKey = format.getByteBuffer("crypto-key");
- if (cryptoKey != null) {
- byte[] dst = new byte[cryptoKey.remaining()];
- cryptoKey.get(dst);
- return dst;
- }
+ for (MediaExtractor ex: new MediaExtractor[] {mVideoExtractor, mAudioExtractor}) {
+ DrmInitData drmInitData = ex.getDrmInitData();
+ if (drmInitData != null) {
+ DrmInitData.SchemeInitData schemeInitData = drmInitData.get(CLEARKEY_SCHEME_UUID);
+ if (schemeInitData != null && schemeInitData.data != null) {
+ return schemeInitData.data;
}
}
- return new byte[0];
- } else {
- throw new IllegalArgumentException(
- "initDataType must be one of {\"cenc\", \"webm\"}: " + mDrmInitDataType);
}
+ // TODO
+ // Should not happen after we get content that has the clear key system id.
+ return PSSH;
}
private void prepareAudio() throws IOException {
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
index 0272298..952e03f 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
@@ -48,10 +48,10 @@
FileCopyHelper copier = new FileCopyHelper(mContext);
String fileName = "test" + System.currentTimeMillis();
- copier.copy(R.raw.testmp3, fileName);
-
- File dir = getContext().getFilesDir();
+ File dir = getContext().getExternalFilesDir(null);
mMediaFile = new File(dir, fileName);
+ copier.copyToExternalStorage(R.raw.testmp3, mMediaFile);
+
assertTrue(mMediaFile.exists());
}
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index e211682..bdd190f 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -82,8 +82,10 @@
private boolean mHasVideo = false;
private boolean mEosAudio = false;
private boolean mEosVideo = false;
+ private int mTaggedAudioBufferIndex = -1;
private final Object mConditionEos = new Object();
private final Object mConditionEosAudio = new Object();
+ private final Object mConditionTaggedAudioBufferIndex = new Object();
private int mNumBuffersReturned = 0;
@@ -138,15 +140,23 @@
return ((!mHasVideo || mEosVideo) && (!mHasAudio || mEosAudio));
}
+ public void onTaggedAudioBufferIndex(Decoder decoder, int index) {
+ synchronized (mConditionTaggedAudioBufferIndex) {
+ if (decoder == mDecoderAudio) {
+ mTaggedAudioBufferIndex = index;
+ }
+ }
+ }
+
public void onEos(Decoder decoder) {
- synchronized(mConditionEosAudio) {
+ synchronized (mConditionEosAudio) {
if (decoder == mDecoderAudio) {
mEosAudio = true;
mConditionEosAudio.notify();
}
}
- synchronized(mConditionEos) {
+ synchronized (mConditionEos) {
if (decoder == mDecoderVideo) {
mEosVideo = true;
}
@@ -173,7 +183,7 @@
}
assertTrue("The stream in test file can not be decoded",
- mDecoderAudio.setup(INPUT_RESOURCE_ID, null, Long.MAX_VALUE));
+ mDecoderAudio.setup(INPUT_RESOURCE_ID, null, Long.MAX_VALUE, NO_TIMESTAMP));
// get audio track.
mAudioTrack = mDecoderAudio.getAudioTrack();
@@ -222,7 +232,7 @@
final Object condition = new Object();
mHasAudio = true;
- if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE) == false) {
+ if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE, NO_TIMESTAMP) == false) {
return true;
}
@@ -283,7 +293,7 @@
returnedIndex[0] = -1;
mHasAudio = true;
- if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE) == false) {
+ if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE, NO_TIMESTAMP) == false) {
return true;
}
@@ -417,8 +427,8 @@
boolean audio,
boolean video,
float playbackRate) {
- // allow 250ms for playback to get to stable state.
- final int PLAYBACK_RAMP_UP_TIME_MS = 250;
+ // allow 750ms for playback to get to stable state.
+ final int PLAYBACK_RAMP_UP_TIME_US = 750000;
final Object conditionFirstAudioBuffer = new Object();
@@ -427,14 +437,16 @@
mSurface = mMediaSync.createInputSurface();
if (mDecoderVideo.setup(
- inputResourceId, mSurface, lastBufferTimestampUs) == false) {
+ inputResourceId, mSurface, lastBufferTimestampUs, NO_TIMESTAMP) == false) {
return true;
}
mHasVideo = true;
}
if (audio) {
- if (mDecoderAudio.setup(inputResourceId, null, lastBufferTimestampUs) == false) {
+ if (mDecoderAudio.setup(
+ inputResourceId, null, lastBufferTimestampUs,
+ PLAYBACK_RAMP_UP_TIME_US) == false) {
return true;
}
@@ -452,7 +464,12 @@
decoderAudio.releaseOutputBuffer(bufferIndex, NO_TIMESTAMP);
}
synchronized (conditionFirstAudioBuffer) {
- conditionFirstAudioBuffer.notify();
+ synchronized (mConditionTaggedAudioBufferIndex) {
+ if (mTaggedAudioBufferIndex >= 0
+ && mTaggedAudioBufferIndex == bufferIndex) {
+ conditionFirstAudioBuffer.notify();
+ }
+ }
}
}
}, null);
@@ -484,13 +501,6 @@
}
if (audio) {
- try {
- Thread.sleep(PLAYBACK_RAMP_UP_TIME_MS);
- } catch (InterruptedException e) {
- Log.i(LOG_TAG, "worker thread is interrupted during sleeping.");
- return true;
- }
-
MediaTimestamp mediaTimestamp = mMediaSync.getTimestamp();
assertTrue("No timestamp available for starting", mediaTimestamp != null);
long checkStartTimeRealUs = System.nanoTime() / 1000;
@@ -542,6 +552,7 @@
private MediaSync mMediaSync = null;
private boolean mIsAudio = false;
private long mLastBufferTimestampUs = 0;
+ private long mStartingAudioTimestampUs = NO_TIMESTAMP;
private Surface mSurface = null;
@@ -577,7 +588,9 @@
mIsAudio = isAudio;
}
- public boolean setup(int inputResourceId, Surface surface, long lastBufferTimestampUs) {
+ public boolean setup(
+ int inputResourceId, Surface surface, long lastBufferTimestampUs,
+ long startingAudioTimestampUs) {
if (!mIsAudio) {
mSurface = surface;
// handle video callback in a separate thread as releaseOutputBuffer is blocking
@@ -586,6 +599,7 @@
mHandler = new Handler(mHandlerThread.getLooper());
}
mLastBufferTimestampUs = lastBufferTimestampUs;
+ mStartingAudioTimestampUs = startingAudioTimestampUs;
try {
// get extrator.
String type = mIsAudio ? "audio/" : "video/";
@@ -728,13 +742,18 @@
if (info.size > 0) {
if (mIsAudio) {
ByteBuffer outputByteBuffer = codec.getOutputBuffer(index);
- synchronized(mAudioBufferLock) {
+ synchronized (mAudioBufferLock) {
mAudioBuffers.add(new AudioBuffer(outputByteBuffer, index));
}
mMediaSync.queueAudio(
outputByteBuffer,
index,
info.presentationTimeUs);
+ if (mStartingAudioTimestampUs >= 0
+ && info.presentationTimeUs >= mStartingAudioTimestampUs) {
+ mMediaSyncTest.onTaggedAudioBufferIndex(this, index);
+ mStartingAudioTimestampUs = NO_TIMESTAMP;
+ }
} else {
codec.releaseOutputBuffer(index, info.presentationTimeUs * 1000);
}
@@ -753,7 +772,7 @@
}
public void checkReturnedAudioBuffer(ByteBuffer byteBuffer, int bufferIndex) {
- synchronized(mAudioBufferLock) {
+ synchronized (mAudioBufferLock) {
AudioBuffer audioBuffer = mAudioBuffers.get(0);
if (audioBuffer.mByteBuffer != byteBuffer
|| audioBuffer.mBufferIndex != bufferIndex) {
diff --git a/tests/tests/media/src/android/media/cts/RingtoneTest.java b/tests/tests/media/src/android/media/cts/RingtoneTest.java
index 3527b1a..de21bdd 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneTest.java
@@ -54,7 +54,14 @@
mAudioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume / 2,
AudioManager.FLAG_ALLOW_RINGER_MODES);
// make sure that we are not in silent mode
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
mDefaultRingUri = RingtoneManager.getActualDefaultRingtoneUri(mContext,
RingtoneManager.TYPE_RINGTONE);
@@ -80,7 +87,14 @@
mRingtone.setStreamType(mOriginalStreamType);
}
if (mAudioManager != null) {
- mAudioManager.setRingerMode(mOriginalRingerMode);
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(mOriginalRingerMode);
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
mAudioManager.setStreamVolume(AudioManager.STREAM_RING, mOriginalVolume,
AudioManager.FLAG_ALLOW_RINGER_MODES);
}
diff --git a/tests/tests/os/AndroidManifest.xml b/tests/tests/os/AndroidManifest.xml
index deb7045..bdb5230 100644
--- a/tests/tests/os/AndroidManifest.xml
+++ b/tests/tests/os/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.os">
+ package="android.os.cts">
<permission android:name="android.os.cts.permission.TEST_GRANTED"
android:protectionLevel="normal"
@@ -132,7 +132,7 @@
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.os"
+ android:targetPackage="android.os.cts"
android:label="CTS tests of android.os">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/os/AndroidTest.xml b/tests/tests/os/AndroidTest.xml
index 1676c88..fd446c2 100644
--- a/tests/tests/os/AndroidTest.xml
+++ b/tests/tests/os/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="test-file-name" value="CtsOsTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.cts.os" />
+ <option name="package" value="android.os.cts" />
<option name="runtime-hint" value="3m15s" />
</test>
</configuration>
diff --git a/tests/tests/os/res/raw/test1_new.obb b/tests/tests/os/res/raw/test1_new.obb
new file mode 100644
index 0000000..450af90
--- /dev/null
+++ b/tests/tests/os/res/raw/test1_new.obb
Binary files differ
diff --git a/tests/tests/os/res/xml/alias.xml b/tests/tests/os/res/xml/alias.xml
index 1166669..98fb5b2 100644
--- a/tests/tests/os/res/xml/alias.xml
+++ b/tests/tests/os/res/xml/alias.xml
@@ -19,7 +19,7 @@
<alias xmlns:android="http://schemas.android.com/apk/res/android">
<intent android:action="android.intent.action.MAIN"
- android:targetPackage="com.android.cts.os"
+ android:targetPackage="android.os.cts"
android:targetClass="android.os.cts.ChildActivity"
android:data="http://www.google.com/">
</intent>
diff --git a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java
index 679a35c..a6a6b99 100644
--- a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java
@@ -89,10 +89,10 @@
// Bring up both remote processes and wire them to each other
redIntent = new Intent();
redIntent.setComponent(new ComponentName(
- "com.android.cts.os", "android.os.cts.ParcelFileDescriptorPeer$Red"));
+ "android.os.cts", "android.os.cts.ParcelFileDescriptorPeer$Red"));
blueIntent = new Intent();
blueIntent.setComponent(new ComponentName(
- "com.android.cts.os", "android.os.cts.ParcelFileDescriptorPeer$Blue"));
+ "android.os.cts", "android.os.cts.ParcelFileDescriptorPeer$Blue"));
redConn = new PeerConnection();
blueConn = new PeerConnection();
context.startService(redIntent);
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index 90473d7..355ef65 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -16,7 +16,7 @@
package android.os.storage.cts;
-import com.android.cts.os.R;
+import android.os.cts.R;
import android.content.Context;
import android.content.res.Resources;
@@ -47,7 +47,7 @@
private static final long WAIT_TIME_INCR = 5*1000;
private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
- private static final String TEST1_CONTENTS = "1\n";
+ private static final String TEST1_NEW_CONTENTS = "1\n";
private StorageManager mStorageManager;
@@ -59,16 +59,16 @@
public void testMountAndUnmountObbNormal() throws IOException {
for (File target : getTargetFiles()) {
- target = new File(target, "test1.obb");
+ target = new File(target, "test1_new.obb");
Log.d(TAG, "Testing path " + target);
doMountAndUnmountObbNormal(target);
}
}
private void doMountAndUnmountObbNormal(File outFile) throws IOException {
- final String canonPath = mountObb(R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED);
+ final String canonPath = mountObb(R.raw.test1_new, outFile, OnObbStateChangeListener.MOUNTED);
- mountObb(R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
+ mountObb(R.raw.test1_new, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
try {
final String mountPath = checkMountedPath(canonPath);
@@ -77,7 +77,7 @@
assertTrue("OBB mounted path should be a directory", mountDir.isDirectory());
assertTrue("test1.txt does not exist in OBB dir", testFile.exists());
- assertFileContains(testFile, TEST1_CONTENTS);
+ assertFileContains(testFile, TEST1_NEW_CONTENTS);
} finally {
unmountObb(outFile, OnObbStateChangeListener.UNMOUNTED);
}
@@ -130,8 +130,8 @@
}
private void doMountAndUnmountTwoObbs(File file1, File file2) throws IOException {
- ObbObserver oo1 = mountObbWithoutWait(R.raw.test1, file1);
- ObbObserver oo2 = mountObbWithoutWait(R.raw.test1, file2);
+ ObbObserver oo1 = mountObbWithoutWait(R.raw.test1_new, file1);
+ ObbObserver oo2 = mountObbWithoutWait(R.raw.test1_new, file2);
Log.d(TAG, "Waiting for OBB #1 to complete mount");
waitForObbActionCompletion(file1, oo1, OnObbStateChangeListener.MOUNTED);
@@ -144,14 +144,14 @@
final File testFile1 = new File(mountDir1, "test1.txt");
assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory());
assertTrue("test1.txt does not exist in OBB dir", testFile1.exists());
- assertFileContains(testFile1, TEST1_CONTENTS);
+ assertFileContains(testFile1, TEST1_NEW_CONTENTS);
final String mountPath2 = checkMountedPath(oo2.getPath());
final File mountDir2 = new File(mountPath2);
final File testFile2 = new File(mountDir2, "test1.txt");
assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory());
assertTrue("test1.txt does not exist in OBB dir", testFile2.exists());
- assertFileContains(testFile2, TEST1_CONTENTS);
+ assertFileContains(testFile2, TEST1_NEW_CONTENTS);
} finally {
unmountObb(file1, OnObbStateChangeListener.UNMOUNTED);
unmountObb(file2, OnObbStateChangeListener.UNMOUNTED);
@@ -308,7 +308,7 @@
private void unmountObb(final File file, int expectedState) {
final ObbObserver observer = new ObbObserver();
- assertTrue("unmountObb call on test1.obb should succeed",
+ assertTrue("unmountObb call on test1_new.obb should succeed",
mStorageManager.unmountObb(file.getPath(), false, observer));
assertTrue("Unmount should have completed",
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index bc7119c..9024092 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -87,6 +87,7 @@
<protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
<protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
@@ -265,6 +266,7 @@
<protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
<protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+ <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
@@ -374,7 +376,10 @@
<protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
<protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
<protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
<protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
@@ -412,6 +417,7 @@
<protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
<protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
+ <protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" />
<protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" />
<protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" />
<protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
@@ -432,7 +438,6 @@
<protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
<protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
- <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
<protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
<protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
@@ -450,6 +455,13 @@
<protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
+ <protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
+ <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+ <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+
+ <!-- @hide UCE service Notification -->
+ <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -694,7 +706,9 @@
android:description="@string/permgroupdesc_phone"
android:priority="500" />
- <!-- Allows read only access to phone state.
+ <!-- Allows read only access to phone state, including the phone number of the device,
+ current cellular network information, the status of any ongoing calls, and a list of any
+ {@link android.telecom.PhoneAccount}s registered on the device.
<p class="note"><strong>Note:</strong> If <em>both</em> your <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
minSdkVersion}</a> and <a
@@ -823,6 +837,26 @@
android:protectionLevel="dangerous"/>
<!-- ====================================================================== -->
+ <!-- Permissions for accessing the UCE Service -->
+ <!-- ====================================================================== -->
+
+ <!-- @hide Allows an application to Access UCE-Presence.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="dangerous"/>
+
+ <!-- @hide Allows an application to Access UCE-OPTIONS.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="dangerous"/>
+
+
+
+ <!-- ====================================================================== -->
<!-- Permissions for accessing the device camera -->
<!-- ====================================================================== -->
<eat-comment />
@@ -965,16 +999,6 @@
<!-- INSTALL PERMISSIONS -->
<!-- ====================================================================== -->
- ` <!-- =========================================== -->
- <!-- Permissions for accessing contact metadata -->
- <!-- =========================================== -->
- <eat-comment />
-
- <!-- @SystemApi Allows an application to read/write contact metadata.
- <p>Not for use by third-party applications. -->
- <permission android:name="android.permission.READ_WRITE_CONTACT_METADATA"
- android:protectionLevel="signature|system" />
-
<!-- ================================== -->
<!-- Permissions for accessing messages -->
<!-- ================================== -->
@@ -986,6 +1010,11 @@
<permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an application to filter carrier specific sms.
@hide -->
<permission android:name="android.permission.CARRIER_FILTER_SMS"
@@ -1255,7 +1284,7 @@
<!-- ================================== -->
<eat-comment />
- <!-- Allows applications to enter Wi-Fi Multicast mode.
+ <!-- Allows applications to enter Wi-Fi ffMulticast mode.
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
@@ -1480,11 +1509,21 @@
<!-- Allows an application to manage access to documents, usually as part
of a document picker.
+ <p>This permission should <em>only</em> be requested by the platform
+ document management app. This permission cannot be granted to
+ third-party apps.
<p>Protection level: signature
-->
<permission android:name="android.permission.MANAGE_DOCUMENTS"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to cache content.
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.CACHE_CONTENT"
+ android:protectionLevel="signature" />
+
<!-- ================================== -->
<!-- Permissions for screenlock -->
<!-- ================================== -->
@@ -1608,6 +1647,11 @@
<permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows use of PendingIntent.getIntent().
+ @hide -->
+ <permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
+ android:protectionLevel="signature" />
+
<!-- ================================== -->
<!-- Permissions affecting the display of other applications -->
<!-- ================================== -->
@@ -2128,6 +2172,15 @@
<permission android:name="android.permission.BIND_PRINT_SERVICE"
android:protectionLevel="signature" />
+ <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
+ to ensure that only the system can bind to it.
+ @hide
+ @SystemApi
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
the system can bind to it.
@@ -2695,7 +2748,7 @@
OTA reboot *not* occur while the lock is held.
@hide -->
<permission android:name="android.permission.UPDATE_LOCK"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|fvprivileged" />
<!-- @SystemApi Allows an application to read the current set of notifications, including
any metadata and intents attached.
@@ -2766,12 +2819,11 @@
android:protectionLevel="signature" />
<!-- Must be required by an {@link
- android.service.notification.NotificationAssistantService},
- to ensure that only the system can bind to it.
+ android.service.notification.NotificationRankerService to ensure that only the system can bind to it.
<p>Protection level: signature
@hide This is not a third-party API (intended for system apps). -->
-->
- <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
+ <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
android:protectionLevel="signature" />
<!-- Must be required by a {@link
@@ -2926,6 +2978,12 @@
<permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
+ the system can bind to it.
+ <p>Protection level: signature -->
+ <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
@@ -2935,9 +2993,9 @@
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android"
android:supportsRtl="true"
- android:theme="@style/Theme.Material.DayNight.DarkActionBar"
- android:forceDeviceEncrypted="true"
- android:encryptionAware="true">
+ android:theme="@style/Theme.Material.Light.DarkActionBar"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.DeviceDefault.Resolver"
android:finishOnCloseSystemDialogs="true"
@@ -2971,7 +3029,7 @@
android:label="@string/managed_profile_label">
</activity-alias>
<activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/heavy_weight_switcher_title"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
@@ -3004,7 +3062,7 @@
<activity android:name="android.accounts.ChooseAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
@@ -3012,14 +3070,14 @@
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
android:excludeFromRecents="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
@@ -3027,19 +3085,19 @@
<activity android:name="android.accounts.CantAddAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog.NoActionBar"
+ android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
android:process=":ui">
</activity>
<activity android:name="android.accounts.GrantCredentialsPermissionActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.DialogWhenLarge"
+ android:theme="@style/Theme.Material.Light.DialogWhenLarge"
android:process=":ui">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/sync_too_many_deletes"
android:process=":ui">
</activity>
@@ -3059,7 +3117,7 @@
</activity>
<activity android:name="com.android.internal.app.NetInitiatedActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
@@ -3080,7 +3138,7 @@
<activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
android:excludeFromRecents="true"
android:process=":ui"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert">
<intent-filter android:priority="1000">
<action android:name="android.os.action.CREATE_USER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3088,7 +3146,7 @@
</activity>
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 44f9ff1..7a31e5f 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -105,6 +105,7 @@
private CallCounter mWriteCallCounter;
private CallCounter mFinishCallCounter;
private CallCounter mPrintJobQueuedCallCounter;
+ private CallCounter mCreateSessionCallCounter;
private CallCounter mDestroySessionCallCounter;
private String[] mEnabledImes;
@@ -189,6 +190,7 @@
mWriteCallCounter = new CallCounter();
mFinishCallCounter = new CallCounter();
mPrintJobQueuedCallCounter = new CallCounter();
+ mCreateSessionCallCounter = new CallCounter();
mDestroySessionCallCounter = new CallCounter();
// Create the activity for the right locale.
@@ -261,6 +263,10 @@
mPrintJobQueuedCallCounter.call();
}
+ protected void onPrinterDiscoverySessionCreateCalled() {
+ mCreateSessionCallCounter.call();
+ }
+
protected void onPrinterDiscoverySessionDestroyCalled() {
mDestroySessionCallCounter.call();
}
@@ -270,6 +276,11 @@
"Did not get expected call to onCancel for the current operation.");
}
+ protected void waitForPrinterDiscoverySessionCreateCallbackCalled() {
+ waitForCallbackCallCount(mCreateSessionCallCounter, 1,
+ "Did not get expected call to onCreatePrinterDiscoverySession.");
+ }
+
protected void waitForPrinterDiscoverySessionDestroyCallbackCalled() {
waitForCallbackCallCount(mDestroySessionCallCounter, 1,
"Did not get expected call to onDestroyPrinterDiscoverySession.");
diff --git a/tests/tests/print/src/android/print/cts/ClassParametersTest.java b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
new file mode 100644
index 0000000..bad47f8
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentInfo;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test that the print attributes are correctly propagated through the print framework
+ */
+@RunWith(AndroidJUnit4.class)
+public class ClassParametersTest {
+ /**
+ * Run a runnable and expect and exception of a certain type.
+ *
+ * @param r The runnable to run
+ * @param expectedClass The expected exception type
+ */
+ private void assertException(Runnable r, Class<? extends RuntimeException> expectedClass) {
+ try {
+ r.run();
+ } catch (Exception e) {
+ if (e.getClass().isAssignableFrom(expectedClass)) {
+ return;
+ } else {
+ throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+ + e.getClass().getName());
+ }
+ }
+
+ throw new AssertionError("No exception thrown");
+ }
+
+ /**
+ * Test that we cannot create PrintAttributes with illegal parameters.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ @Test
+ public void testIllegalPrintAttributes() throws Exception {
+ assertException(() -> (new PrintAttributes.Builder()).setColorMode(-1),
+ IllegalArgumentException.class);
+ assertException(() -> (new PrintAttributes.Builder()).setColorMode(0),
+ IllegalArgumentException.class);
+ assertException(() -> (new PrintAttributes.Builder()).setColorMode(
+ PrintAttributes.COLOR_MODE_COLOR | PrintAttributes.COLOR_MODE_MONOCHROME),
+ IllegalArgumentException.class);
+
+ assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(-1),
+ IllegalArgumentException.class);
+ assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(0),
+ IllegalArgumentException.class);
+ assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(
+ PrintAttributes.DUPLEX_MODE_LONG_EDGE | PrintAttributes.DUPLEX_MODE_NONE),
+ IllegalArgumentException.class);
+
+ assertException(() -> new Resolution(null, "label", 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("", "label", 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("id", null, 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("id", "", 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("id", "label", -10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("id", "label", 0, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("id", "label", 10, -10),
+ IllegalArgumentException.class);
+ assertException(() -> new Resolution("id", "label", 10, 0),
+ IllegalArgumentException.class);
+
+ assertException(() -> new MediaSize(null, "label", 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("", "label", 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("id", null, 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("id", "", 10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("id", "label", -10, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("id", "label", 0, 10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("id", "label", 10, -10),
+ IllegalArgumentException.class);
+ assertException(() -> new MediaSize("id", "label", 10, 0),
+ IllegalArgumentException.class);
+
+ // There is no restrictions on what parameters to set for minMargins.
+ }
+
+ /**
+ * Test that we cannot create PrintDocumentInfo with illegal parameters.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ @Test
+ public void testIllegalPrintDocumentInfo() throws Exception {
+ assertException(() -> new PrintDocumentInfo.Builder(null),
+ IllegalArgumentException.class);
+ assertException(() -> new PrintDocumentInfo.Builder(""),
+ IllegalArgumentException.class);
+
+ assertException(() -> new PrintDocumentInfo.Builder("doc").setPageCount(-2),
+ IllegalArgumentException.class);
+ // -1 == UNKNOWN and 0 are allowed
+
+ // Content type is not restricted
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
index 855f587..1b8c318 100644
--- a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
@@ -637,7 +637,7 @@
*
* @throws Exception If anything is unexpected
*/
- public void testIllegalSuggested() throws Exception {
+ public void testUnsupportedSuggested() throws Exception {
// available default suggestion
baseTest( MIN_MARGINS[0],
Arrays.copyOfRange(MEDIA_SIZES, 0, 1), MEDIA_SIZES[0], MEDIA_SIZES[1],
@@ -645,4 +645,19 @@
Arrays.copyOfRange(DUPLEX_MODES, 0, 1), DUPLEX_MODES[0], DUPLEX_MODES[1],
Arrays.copyOfRange(RESOLUTIONS, 0, 1), RESOLUTIONS[0], RESOLUTIONS[1]);
}
+
+ /**
+ * Test that negative Margins do not cause issues in the print print spooler. Negative margins
+ * are allowed because of historical reasons.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testNegativeMargins() throws Exception {
+ // available default suggestion
+ baseTest( new Margins(-10, -10, -10, -10),
+ MEDIA_SIZES, MEDIA_SIZES[1], null,
+ COLOR_MODES, COLOR_MODES[1], 0,
+ DUPLEX_MODES, DUPLEX_MODES[1], 0,
+ RESOLUTIONS, RESOLUTIONS[1], null);
+ }
}
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index 7d0157b..b539a83 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -1665,6 +1665,154 @@
waitForPrinterDiscoverySessionDestroyCallbackCalled();
}
+ /**
+ * Executes a print process with a given print document info
+ *
+ * @param info The print document info to declare on layout
+ */
+ private void printDocumentInfoBaseTest(final PrintDocumentInfo info) throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ final PrintAttributes[] printAttributes = new PrintAttributes[1];
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ writeBlankPages(printAttributes[0], fd, 0, 1);
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Select the second printer.
+ selectPrinter("Second printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
+ // Wait for the session to be destroyed to isolate tests.
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+ }
+
+ /**
+ * Test that the default values of the PrintDocumentInfo are fine.
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoNothingSet() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME)).build());
+ }
+
+ /**
+ * Test that a unknown page count is handled correctly.
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoUnknownPageCount() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).build());
+ }
+
+ /**
+ * Test that zero page count is handled correctly.
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoZeroPageCount() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setPageCount(0).build());
+ }
+
+ /**
+ * Test that page count one is handled correctly. (The document has two pages)
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoOnePageCount() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setPageCount(1).build());
+ }
+
+ /**
+ * Test that page count three is handled correctly. (The document has two pages)
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoThreePageCount() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setPageCount(3).build());
+ }
+
+ /**
+ * Test that a photo content type is handled correctly.
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoContentTypePhoto() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO).build());
+ }
+
+ /**
+ * Test that a unknown content type is handled correctly.
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoContentTypeUnknown() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_UNKNOWN).build());
+ }
+
+ /**
+ * Test that a undefined content type is handled correctly.
+ *
+ * @throws Exception If anything unexpected happens
+ */
+ public void testDocumentInfoContentTypeNonDefined() throws Exception {
+ printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+ .setContentType(-23).build());
+ }
+
private PrintServiceCallbacks createFirstMockPrintServiceCallbacks() {
final PrinterDiscoverySessionCallbacks callbacks =
createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
index 2ed21b9..1df068d 100644
--- a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
@@ -43,6 +43,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* This test verifies changes to the printer capabilities are applied correctly.
@@ -51,8 +53,14 @@
private static final String LOG_TAG = "PrinterCapabilitiesTest";
private static final String PRINTER_NAME = "Test printer";
+ private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
+ private static final PrintAttributes.Resolution RESOLUTION_300 =
+ new PrintAttributes.Resolution("300", "300", 300, 300);
+ private static final PrintAttributes.Resolution RESOLUTION_600 =
+ new PrintAttributes.Resolution("600", "600", 600, 600);
+
/**
- * Generate a new list of printers containing a singler printer with the given media size and
+ * Generate a new list of printers containing a singer printer with the given media size and
* status. The other capabilities are default values.
*
* @param printerId The id of the printer
@@ -70,13 +78,13 @@
if (mediaSize != null) {
PrinterCapabilitiesInfo.Builder builder = new PrinterCapabilitiesInfo.Builder(
printerId);
- builder.setMinMargins(new Margins(0, 0, 0, 0))
+ builder.setMinMargins(DEFAULT_MARGINS)
.setColorModes(PrintAttributes.COLOR_MODE_COLOR,
PrintAttributes.COLOR_MODE_COLOR)
.setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
PrintAttributes.DUPLEX_MODE_NONE)
.addMediaSize(mediaSize, true)
- .addResolution(new Resolution("300x300", "300x300", 300, 300), true);
+ .addResolution(RESOLUTION_300, true);
cap = builder.build();
} else {
cap = null;
@@ -339,4 +347,409 @@
waitForPrinterDiscoverySessionDestroyCallbackCalled();
}
+
+ /**
+ * Run a runnable and expect and exception of a certain type.
+ *
+ * @param r The runnable to run
+ * @param expectedClass The expected exception type
+ */
+ private void assertException(Runnable r, Class<? extends RuntimeException> expectedClass) {
+ try {
+ r.run();
+ } catch (Exception e) {
+ if (e.getClass().isAssignableFrom(expectedClass)) {
+ return;
+ } else {
+ throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+ + e.getClass().getName());
+ }
+ }
+
+ throw new AssertionError("No exception thrown");
+ }
+
+ /**
+ * That that you cannot create illegal PrinterCapabilityInfos.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testIllegalPrinterCapabilityInfos() throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+ createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ StubbablePrinterDiscoverySession session =
+ ((PrinterDiscoverySessionCallbacks)
+ invocation.getMock()).getSession();
+
+ PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+
+ // printerId need to be set
+ assertException(() -> new PrinterCapabilitiesInfo.Builder(null),
+ IllegalArgumentException.class);
+
+ // All capability fields (beside duplex) need to be initialized:
+ // Test no color
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setMinMargins(DEFAULT_MARGINS)
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(RESOLUTION_300, true).build(),
+ IllegalStateException.class);
+ // Test bad colors
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setColorModes(0xffff,
+ PrintAttributes.COLOR_MODE_MONOCHROME),
+ IllegalArgumentException.class);
+ // Test bad duplex mode
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setDuplexModes(0xffff,
+ PrintAttributes.DUPLEX_MODE_NONE),
+ IllegalArgumentException.class);
+ // Test no mediasize
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .setMinMargins(DEFAULT_MARGINS)
+ .addResolution(RESOLUTION_300, true).build(),
+ IllegalStateException.class);
+ // Test no default mediasize
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .setMinMargins(DEFAULT_MARGINS)
+ .addMediaSize(MediaSize.ISO_A4, false)
+ .addResolution(RESOLUTION_300, true).build(),
+ IllegalStateException.class);
+ // Test two default mediasizes
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addMediaSize(MediaSize.ISO_A5, true),
+ IllegalArgumentException.class);
+ // Test no resolution
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .setMinMargins(DEFAULT_MARGINS)
+ .addMediaSize(MediaSize.ISO_A4, true).build(),
+ IllegalStateException.class);
+ // Test no default resolution
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .setMinMargins(DEFAULT_MARGINS)
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(RESOLUTION_300, false).build(),
+ IllegalStateException.class);
+ // Test two default resolutions
+ assertException(() ->
+ (new PrinterCapabilitiesInfo.Builder(printerId))
+ .addResolution(RESOLUTION_300, true)
+ .addResolution(RESOLUTION_600, true),
+ IllegalArgumentException.class);
+
+ onPrinterDiscoverySessionCreateCalled();
+ return null;
+ }
+ }, null, null, null, null, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ }
+ });
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return firstSessionCallbacks;
+ }
+ }, null, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+ PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(null, null, null);
+
+ // Start printing.
+ print(adapter);
+
+ waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+ getUiDevice().pressBack();
+
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+ }
+
+ /**
+ * That that you can use all sane legal PrinterCapabilityInfos.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testSanePrinterCapabilityInfos() throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+ createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ StubbablePrinterDiscoverySession session =
+ ((PrinterDiscoverySessionCallbacks)
+ invocation.getMock()).getSession();
+
+ MediaSize[] mediaSizes = {MediaSize.ISO_A0, MediaSize.ISO_A0,
+ MediaSize.ISO_A1};
+ Resolution[] resolutions = {RESOLUTION_300, RESOLUTION_300,
+ RESOLUTION_600};
+ int[] colorModes = {PrintAttributes.COLOR_MODE_MONOCHROME,
+ PrintAttributes.COLOR_MODE_COLOR};
+ int[] duplexModes = {PrintAttributes.DUPLEX_MODE_NONE,
+ PrintAttributes.DUPLEX_MODE_LONG_EDGE,
+ PrintAttributes.DUPLEX_MODE_SHORT_EDGE};
+
+ ArrayList<PrinterInfo> printers = new ArrayList<>();
+ for (int mediaSizeIndex = 1; mediaSizeIndex < mediaSizes.length;
+ mediaSizeIndex++) {
+ for (int resolutionIndex = 1; resolutionIndex < mediaSizes.length;
+ resolutionIndex++) {
+ for (int colorIndex = 1; colorIndex < colorModes.length;
+ colorIndex++) {
+ for (int duplexIndex = 1; duplexIndex < duplexModes.length;
+ duplexIndex++) {
+ PrinterId printerId = session.getService()
+ .generatePrinterId(Integer.valueOf(printers.size())
+ .toString());
+
+ PrinterCapabilitiesInfo.Builder b =
+ new PrinterCapabilitiesInfo.Builder(printerId);
+
+ for (int i = 0; i < mediaSizeIndex; i++) {
+ b.addMediaSize(mediaSizes[i], i == mediaSizeIndex - 1);
+ }
+
+ for (int i = 0; i < resolutionIndex; i++) {
+ b.addResolution(resolutions[i],
+ i == resolutionIndex - 1);
+ }
+
+ int allColors = 0;
+ for (int i = 0; i < colorIndex; i++) {
+ allColors |= colorModes[i];
+ }
+ b.setColorModes(allColors, colorModes[colorIndex - 1]);
+
+ int allDuplexModes = 0;
+ for (int i = 0; i < duplexIndex; i++) {
+ allDuplexModes |= duplexModes[i];
+ }
+ b.setDuplexModes(allDuplexModes,
+ duplexModes[duplexIndex - 1]);
+
+ printers.add((new PrinterInfo.Builder(printerId,
+ Integer.valueOf(printers.size()).toString(),
+ PrinterInfo.STATUS_IDLE)).setCapabilities(b.build())
+ .build());
+ }
+ }
+ }
+ }
+
+ session.addPrinters(printers);
+
+ onPrinterDiscoverySessionCreateCalled();
+ return null;
+ }
+ }, null, null, null, null, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ }
+ });
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return firstSessionCallbacks;
+ }
+ }, null, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+ PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(null, null, null);
+
+ // Start printing.
+ print(adapter);
+
+ waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+ getUiDevice().pressBack();
+
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+ }
+
+ /**
+ * Base test that performs a print operation with a give PrinterCapabilityInfo and run a test
+ * function before finishing.
+ *
+ * @throws Exception
+ */
+ private void testPrinterCapabilityInfo(final Function<PrinterId, PrinterCapabilitiesInfo>
+ capBuilder, Consumer<PrintAttributes> test) throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+ createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ StubbablePrinterDiscoverySession session =
+ ((PrinterDiscoverySessionCallbacks)
+ invocation.getMock()).getSession();
+
+ PrinterId printerId = session.getService()
+ .generatePrinterId(PRINTER_NAME);
+
+ ArrayList<PrinterInfo> printers = new ArrayList<>();
+ printers.add((new PrinterInfo.Builder(printerId, PRINTER_NAME,
+ PrinterInfo.STATUS_IDLE))
+ .setCapabilities(capBuilder.apply(printerId)).build());
+
+ session.addPrinters(printers);
+
+ onPrinterDiscoverySessionCreateCalled();
+ return null;
+ }
+ }, null, null, null, null, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ }
+ });
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return firstSessionCallbacks;
+ }
+ }, null, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+ final PrintAttributes[] layoutAttributes = new PrintAttributes[1];
+
+ PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation
+ .getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setPageCount(1)
+ .build();
+ layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+
+ callback.onLayoutFinished(info, true);
+ return null;
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+
+ writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(),
+ pages[0].getEnd());
+ fd.close();
+
+ callback.onWriteFinished(pages);
+ return null;
+ }
+ }, null);
+
+ // Start printing.
+ print(adapter);
+
+ // make sure that options does not crash
+ openPrintOptions();
+
+ // Select printer under test
+ selectPrinter(PRINTER_NAME);
+
+ clickPrintButton();
+
+ answerPrintServicesWarning(true);
+
+ test.accept(layoutAttributes[0]);
+
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+ }
+
+ /**
+ * That that you use a default color that is not in the allowed colors. This is allowed because
+ * of historical reasons.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testInvalidDefaultColor() throws Exception {
+ testPrinterCapabilityInfo(
+ (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(RESOLUTION_300, true)
+ .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME,
+ PrintAttributes.COLOR_MODE_COLOR).build(),
+ (layoutAttributes) -> assertEquals(layoutAttributes.getColorMode(),
+ PrintAttributes.COLOR_MODE_MONOCHROME));
+ }
+
+ /**
+ * That that you use a default duplex mode that is not in the allowed duplex modes. This is
+ * allowed because of historical reasons.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testInvalidDefaultDuplexMode() throws Exception {
+ testPrinterCapabilityInfo(
+ (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(RESOLUTION_300, true)
+ .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME,
+ PrintAttributes.COLOR_MODE_MONOCHROME)
+ .setDuplexModes(PrintAttributes.DUPLEX_MODE_LONG_EDGE
+ | PrintAttributes.DUPLEX_MODE_NONE,
+ PrintAttributes.DUPLEX_MODE_SHORT_EDGE).build(),
+ (layoutAttributes) -> assertTrue(layoutAttributes.getDuplexMode() ==
+ PrintAttributes.DUPLEX_MODE_LONG_EDGE || layoutAttributes.getDuplexMode() ==
+ PrintAttributes.DUPLEX_MODE_NONE));
+ }
}
diff --git a/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java b/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
index ed4d5d5..adf558b 100644
--- a/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
@@ -20,13 +20,10 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.provider.BlockedNumberContract;
import android.telecom.Log;
-import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
/**
* CTS tests for backup and restore of blocked numbers using local transport.
*/
@@ -40,13 +37,13 @@
"android/com.android.internal.backup.LocalTransport";
private static final String BLOCKED_NUMBERS_PROVIDER_PACKAGE =
"com.android.providers.blockednumber";
- private static final Pattern BMGR_ENABLED_PATTERN = Pattern.compile(
- "^Backup Manager currently (enabled|disabled)$");
private ContentResolver mContentResolver;
private Context mContext;
private UiAutomation mUiAutomation;
private String mOldTransport;
+ private boolean mOldBackupEnabled;
+ private boolean mHasFeature;
@Override
protected void setUp() throws Exception {
@@ -56,26 +53,36 @@
mContentResolver = mContext.getContentResolver();
mUiAutomation = getInstrumentation().getUiAutomation();
- ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
+ mHasFeature = isFeatureSupported();
- mOldTransport = ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation);
- clearBlockedNumbers();
- wipeBackup();
+ if (mHasFeature) {
+ ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
+
+ mOldTransport = ProviderTestUtils.setBackupTransport(
+ LOCAL_BACKUP_COMPONENT, mUiAutomation);
+ mOldBackupEnabled = ProviderTestUtils.setBackupEnabled(true, mUiAutomation);
+ clearBlockedNumbers();
+ wipeBackup();
+ }
}
@Override
protected void tearDown() throws Exception {
- wipeBackup();
- clearBlockedNumbers();
- ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
- ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
+ if (mHasFeature) {
+ wipeBackup();
+ clearBlockedNumbers();
+ ProviderTestUtils.setBackupEnabled(mOldBackupEnabled, mUiAutomation);
+ ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
+ ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
+ }
super.tearDown();
}
public void testBackupAndRestoreForSingleNumber() throws Exception {
- if (!ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)) {
+ if (!mHasFeature) {
Log.i(TAG, "skipping BlockedNumberBackupRestoreTest");
+ return;
}
Log.i(TAG, "Adding blocked numbers.");
@@ -94,8 +101,9 @@
}
public void testBackupAndRestoreWithDeletion() throws Exception {
- if (!ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)) {
+ if (!mHasFeature) {
Log.i(TAG, "skipping BlockedNumberBackupRestoreTest");
+ return;
}
Log.i(TAG, "Adding blocked numbers.");
@@ -122,6 +130,11 @@
verifyBlockedNumbers("223456789", "323456789");
}
+ private boolean isFeatureSupported() throws Exception {
+ return ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)
+ && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ }
+
private void insertBlockedNumber(String number) {
ContentValues cv = new ContentValues();
cv.put(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number);
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index 874a0a7..e2ed68d 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -34,7 +34,9 @@
*/
public class ProviderTestUtils {
- static final int BACKUP_TIMEOUT_MILLIS = 4000;
+ private static final int BACKUP_TIMEOUT_MILLIS = 4000;
+ private static final Pattern BMGR_ENABLED_PATTERN = Pattern.compile(
+ "^Backup Manager currently (enabled|disabled)$");
static void setDefaultSmsApp(boolean setToSmsApp, String packageName, UiAutomation uiAutomation)
throws Exception {
@@ -73,6 +75,22 @@
}
}
+ static boolean setBackupEnabled(boolean enable, UiAutomation uiAutomation) throws Exception {
+ // Check to see the previous state of the backup service
+ boolean previouslyEnabled = false;
+ String output = executeShellCommand("bmgr enabled", uiAutomation);
+ Matcher matcher = BMGR_ENABLED_PATTERN.matcher(output.trim());
+ if (matcher.find()) {
+ previouslyEnabled = "enabled".equals(matcher.group(1));
+ } else {
+ throw new RuntimeException("Backup output format changed. No longer matches"
+ + " expected regex: " + BMGR_ENABLED_PATTERN + "\nactual: '" + output + "'");
+ }
+
+ executeShellCommand("bmgr enable " + enable, uiAutomation);
+ return previouslyEnabled;
+ }
+
static boolean hasBackupTransport(String transport, UiAutomation uiAutomation)
throws Exception {
String output = executeShellCommand("bmgr list transports", uiAutomation);
diff --git a/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java b/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
index f5e3033..fad1019 100644
--- a/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
@@ -24,6 +24,7 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
@@ -65,6 +66,8 @@
private ContentResolver mContentResolver;
private UiAutomation mUiAutomation;
private String mOldTransport;
+ private boolean mOldBackupEnabled;
+ private boolean mHasFeature;
@Override
protected void setUp() throws Exception {
@@ -74,21 +77,35 @@
mContext = getInstrumentation().getContext();
mContentResolver = mContext.getContentResolver();
mUiAutomation = getInstrumentation().getUiAutomation();
- ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
- mOldTransport = ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation);
- clearMessages();
- wipeBackup();
+ mHasFeature = isFeatureSupported();
+ if (mHasFeature) {
+ ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
+ mOldTransport =
+ ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation);
+ mOldBackupEnabled = ProviderTestUtils.setBackupEnabled(true, mUiAutomation);
+ clearMessages();
+ wipeBackup();
+ }
}
@Override
protected void tearDown() throws Exception {
- wipeBackup();
- clearMessages();
- ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
- ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
+ if (mHasFeature) {
+ wipeBackup();
+ clearMessages();
+ ProviderTestUtils.setBackupEnabled(mOldBackupEnabled, mUiAutomation);
+ ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
+ ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
+ }
+
super.tearDown();
}
+ private boolean isFeatureSupported() throws Exception {
+ return (ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)
+ && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+ }
+
private void clearMessages() {
mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody1);
mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2);
@@ -117,8 +134,9 @@
* @throws Exception
*/
public void testSmsBackupRestore() throws Exception {
- if (!ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)) {
+ if (!mHasFeature) {
Log.i(TAG, "skipping testSmsBackupRestore");
+ return;
}
ContentValues smsContentValues[] = new ContentValues[] {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
index 6e74cb3..bb10716 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
@@ -45,7 +45,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_1D_Padded_Byte Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Byte3_1D Failed, output array does not match input",
result);
}
@@ -54,7 +54,7 @@
int width = random.nextInt(128);
int height = random.nextInt(128);
int arr_len = width * height * 3;
-
+
byte[] inArray = new byte[arr_len];
byte[] outArray = new byte[arr_len];
random.nextBytes(inArray);
@@ -73,7 +73,7 @@
break;
}
}
- assertTrue("test_2D_AllocationCopyTo_Padded_Byte Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Byte3_2D Failed, output array does not match input",
result);
}
@@ -102,7 +102,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_3D_Padded_Byte Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Byte3_3D Failed, output array does not match input",
result);
}
@@ -146,7 +146,7 @@
int width = random.nextInt(128);
int height = random.nextInt(128);
int arr_len = width * height * 3;
-
+
short[] inArray = new short[arr_len];
short[] outArray = new short[arr_len];
@@ -240,7 +240,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_1D_Padded_Int Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Int3_1D Failed, output array does not match input",
result);
}
@@ -249,7 +249,7 @@
int width = random.nextInt(128);
int height = random.nextInt(128);
int arr_len = width * height * 3;
-
+
int[] inArray = new int[arr_len];
int[] outArray = new int[arr_len];
@@ -271,7 +271,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_2D_Padded_Int Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Int3_2D Failed, output array does not match input",
result);
}
@@ -303,7 +303,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_3D_Padded_Int Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Int3_3D Failed, output array does not match input",
result);
}
@@ -333,7 +333,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_1D_Padded_Float Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Float3_1D Failed, output array does not match input",
result);
}
public void test_AllocationPadded_Float3_2D() {
@@ -363,7 +363,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_2D_Padded_Float Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Float3_2D Failed, output array does not match input",
result);
}
public void test_AllocationPadded_Float3_3D() {
@@ -394,7 +394,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_3D_Padded_Float Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Float3_3D Failed, output array does not match input",
result);
}
@@ -424,7 +424,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_1D_Padded_Double Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Double3_1D Failed, output array does not match input",
result);
}
public void test_AllocationPadded_Double3_2D() {
@@ -454,7 +454,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_2D_Padded_Double Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Double3_2D Failed, output array does not match input",
result);
}
public void test_AllocationPadded_Double3_3D() {
@@ -485,7 +485,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_3D_Padded_Double Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Double3_3D Failed, output array does not match input",
result);
}
@@ -515,7 +515,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_1D_Padded_Long Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Long3_1D Failed, output array does not match input",
result);
}
@@ -524,7 +524,7 @@
int width = random.nextInt(128);
int height = random.nextInt(128);
int arr_len = width * height * 3;
-
+
long[] inArray = new long[arr_len];
long[] outArray = new long[arr_len];
@@ -546,7 +546,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_2D_Padded_Long Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Long3_2D Failed, output array does not match input",
result);
}
@@ -578,7 +578,7 @@
break;
}
}
- assertTrue("test_AllocationCopyTo_3D_Padded_Long Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_Long3_3D Failed, output array does not match input",
result);
}
@@ -614,7 +614,7 @@
break;
}
}
- assertTrue("test_copy1DRangeTo_Padded_Byte Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeTo_Byte3, output array does not match input",
result);
}
@@ -625,7 +625,7 @@
short[] inArray = new short[arr_len];
short[] outArray = new short[arr_len];
-
+
for (int i = 0; i < arr_len; i++) {
inArray[i] = (short)random.nextInt();
}
@@ -695,7 +695,7 @@
break;
}
}
- assertTrue("test_copy1DRangeTo_Padded_Int Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeTo_Int3 Failed, output array does not match input",
result);
}
@@ -733,7 +733,7 @@
break;
}
}
- assertTrue("test_copy1DRangeTo_Padded_Float Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeTo_Float3 Failed, output array does not match input",
result);
}
@@ -771,7 +771,7 @@
break;
}
}
- assertTrue("test_copy1DRangeTo_Padded_Long Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeTo_Long3 Failed, output array does not match input",
result);
}
@@ -803,7 +803,7 @@
break;
}
}
- assertTrue("test_copy2DRangeTo_Padded_Byte Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy2DRangeTo_Byte3 Failed, output array does not match input",
result);
}
@@ -819,7 +819,7 @@
short[] inArray = new short[arr_len];
short[] outArray = new short[arr_len];
-
+
for (int i = 0; i < arr_len; i++) {
inArray[i] = (short)random.nextInt();
}
@@ -878,7 +878,7 @@
break;
}
}
- assertTrue("test_copy2DRangeTo_Padded_Int Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy2DRangeTo_Int3 Failed, output array does not match input",
result);
}
@@ -913,7 +913,7 @@
break;
}
}
- assertTrue("test_copy2DRangeTo_Padded_Float Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy2DRangeTo_Float3 Failed, output array does not match input",
result);
}
@@ -948,7 +948,7 @@
break;
}
}
- assertTrue("test_copy2DRangeTo_Padded_Long Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy2DRangeTo_Long3 Failed, output array does not match input",
result);
}
@@ -984,7 +984,7 @@
break;
}
}
- assertTrue("test_copy1DRangeToUnchecked_Padded_Byte Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Byte3 Failed, output array does not match input",
result);
}
@@ -995,7 +995,7 @@
short[] inArray = new short[arr_len];
short[] outArray = new short[arr_len];
-
+
for (int i = 0; i < arr_len; i++) {
inArray[i] = (short)random.nextInt();
}
@@ -1065,7 +1065,7 @@
break;
}
}
- assertTrue("test_copy1DRangeToUnchecked_1D_Padded_Int Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Int3 Failed, output array does not match input",
result);
}
@@ -1103,7 +1103,7 @@
break;
}
}
- assertTrue("test_copy1DRangeToUnchecked_Padded_Float Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Float3 Failed, output array does not match input",
result);
}
@@ -1141,7 +1141,7 @@
break;
}
}
- assertTrue("test_copy1DRangeToUnchecked_Padded_Long Failed, output array does not match input",
+ assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Long3 Failed, output array does not match input",
result);
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
index 37aa85a..bc13144 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
@@ -410,6 +410,10 @@
cbrt(in.max32()));
}
+ static private Target.Floaty clamp(double value, double minValue, double maxValue, Target t) {
+ return t.newFloaty(Math.min(maxValue, Math.max(minValue, value)));
+ }
+
static private Target.Floaty copysign(double magnitude, double sign, Target t) {
return t.newFloaty(Math.copySign(magnitude, sign));
}
@@ -1002,10 +1006,10 @@
Target.Floaty in = t.newFloaty(d);
double min = Math.tan(in.min());
double max = Math.tan(in.max());
- /* If the tan of the min is greater than that of the max,
- * we spanned a discontinuity.
+ /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+ * greater than that of the max, we spanned a discontinuity.
*/
- if (min > max) {
+ if (in.max() - in.min() > Math.PI || min > max) {
return any(t);
} else {
return t.newFloaty(Math.tan(d), min, max);
@@ -1016,10 +1020,10 @@
Target.Floaty in = t.new32(f);
float min = tan(in.min32());
float max = tan(in.max32());
- /* If the tan of the min is greater than that of the max,
- * we spanned a discontinuity.
+ /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+ * greater than that of the max, we spanned a discontinuity.
*/
- if (min > max) {
+ if (in.max() - in.min() > Math.PI || min > max) {
return any32(t);
} else {
return t.new32(tan(f), min, max);
@@ -1046,10 +1050,11 @@
Target.Floaty in = t.multiply(t.newFloaty(d), pi(t));
double min = Math.tan(in.min());
double max = Math.tan(in.max());
- /* If the tan of the min is greater than that of the max,
- * we spanned a discontinuity.
+
+ /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+ * greater than that of the max, we spanned a discontinuity.
*/
- if (min > max) {
+ if (in.max() - in.min() > Math.PI || min > max) {
return any(t);
} else {
return t.newFloaty(Math.tan(in.mid()), min, max);
@@ -1060,10 +1065,10 @@
Target.Floaty in = t.multiply(t.new32(f), pi32(t));
float min = tan(in.min32());
float max = tan(in.max32());
- /* If the tan of the min is greater than that of the max,
- * we spanned a discontinuity.
+ /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+ * greater than that of the max, we spanned a discontinuity.
*/
- if (min > max) {
+ if (in.max() - in.min() > Math.PI || min > max) {
return any32(t);
} else {
return t.new32(tan(in.mid32()), min, max);
@@ -1264,6 +1269,11 @@
args.out = minU32(args.inMaxValue, maxU32(args.inValue, args.inMinValue));
}
+ static public void computeClamp(TestClamp.ArgumentsHalfHalfHalfHalf args, Target t) {
+ t.setPrecision(0, 0);
+ args.out = clamp(args.inValueDouble, args.inMinValueDouble, args.inMaxValueDouble, t);
+ }
+
static public void computeClamp(TestClamp.ArgumentsFloatFloatFloatFloat args, Target t) {
t.setPrecision(0, 0);
args.out = t.new32(Math.min(args.inMaxValue,
@@ -2590,6 +2600,31 @@
args.out = exp2(args.inV, t);
}
+ static public String verifyNativeExpm1(TestNativeExpm1.ArgumentsHalfHalf args, Target t) {
+ // Acceptable error for native_expm1 is:
+ // < 2^-11 in [-Inf, 0.6]
+ // 3 ulp outside
+ double extraAllowedError = 0.;
+ int ulpFactor;
+ if (args.inVDouble < 0.6) {
+ ulpFactor = 0;
+ extraAllowedError = 0.00048828125; // 2^-11
+ } else {
+ ulpFactor = 3;
+ }
+ t.setPrecision(ulpFactor, ulpFactor);
+
+ Target.Floaty expectedOut = expm1(args.inVDouble, t);
+ if (!expectedOut.couldBe(args.outDouble, extraAllowedError)) {
+ StringBuilder message = new StringBuilder();
+ message.append("Ulp Factor: " + Integer.toString(ulpFactor) + "\n");
+ message.append("Extra allowed error: " + Double.toString(extraAllowedError) + "\n");
+ message.append("Expected output out: " + expectedOut.toString() + "\n");
+ return message.toString();
+ }
+ return null;
+ }
+
static public void computeNativeExpm1(TestNativeExpm1.ArgumentsFloatFloat args, Target t) {
t.setPrecision(NATIVE_PRECISION, NATIVE_PRECISION);
args.out = expm1(args.inV, t);
@@ -2826,6 +2861,35 @@
args.out = sqrt(args.inV, t);
}
+ static public String verifyNativeTan(TestNativeTan.ArgumentsHalfHalf args, Target t) {
+ // Precision for native_tan is as follows:
+ // For integral n:
+ // 8 ulp in [(n-0.45) pi, (n+0.45) pi]
+ // 2048 ulp in [(n+0.45) pi, (n+0.55) pi]"
+
+ // Compute the fractional part of args.inVDouble / pi
+ double absoluteValueOverPi = Math.abs(args.inVDouble) / Math.PI;
+ double fract = absoluteValueOverPi - Math.floor(absoluteValueOverPi);
+
+ int ulpFactor;
+ if (0.45 <= fract && fract <= 0.55) {
+ ulpFactor = 2048;
+ } else {
+ ulpFactor = 8;
+ }
+ t.setPrecision(ulpFactor, ulpFactor);
+
+ Target.Floaty expectedOut = tan(args.inVDouble, t);
+ if (!expectedOut.couldBe(args.outDouble)) {
+ StringBuilder message = new StringBuilder();
+ message.append("Ulp Factor: " + Integer.toString(ulpFactor) + "\n");
+ message.append("Expected output out: " + expectedOut.toString() + "\n");
+ return message.toString();
+ }
+
+ return null;
+ }
+
static public void computeNativeTan(TestNativeTan.ArgumentsFloatFloat args, Target t) {
t.setPrecision(NATIVE_PRECISION, NATIVE_PRECISION);
args.out = tan(args.inV, t);
@@ -2841,6 +2905,35 @@
args.out = tanh(args.inV, t);
}
+ static public String verifyNativeTanpi(TestNativeTanpi.ArgumentsHalfHalf args, Target t) {
+ // Precision for native_tan is as follows:
+ // For integral n:
+ // 8 ulp in [(n-0.45), (n+0.45)]
+ // 2048 ulp in [(n+0.45), (n+0.55)]"
+
+ // Compute the fractional part of args.inVDouble
+ double absoluteValue = Math.abs(args.inVDouble);
+ double fract = absoluteValue - Math.floor(absoluteValue);
+
+ int ulpFactor;
+ if (0.45 <= fract && fract <= 0.55) {
+ ulpFactor = 2048;
+ } else {
+ ulpFactor = 8;
+ }
+ t.setPrecision(ulpFactor, ulpFactor);
+
+ Target.Floaty expectedOut = tanpi(args.inVDouble, t);
+ if (!expectedOut.couldBe(args.outDouble)) {
+ StringBuilder message = new StringBuilder();
+ message.append("Ulp Factor: " + Integer.toString(ulpFactor) + "\n");
+ message.append("Expected output out: " + expectedOut.toString() + "\n");
+ return message.toString();
+ }
+
+ return null;
+ }
+
static public void computeNativeTanpi(TestNativeTanpi.ArgumentsFloatFloat args, Target t) {
t.setPrecision(NATIVE_PRECISION, NATIVE_PRECISION);
args.out = tanpi(args.inV, t);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java b/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
index c5b72d1..717c4a0 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
@@ -268,6 +268,22 @@
}
minAlloc.copyFrom(minArray);
maxAlloc.copyFrom(maxArray);
+ } else if (dataType == Element.DataType.FLOAT_16) {
+ short[] minArray = new short[size];
+ short[] maxArray = new short[size];
+ minAlloc.copyTo(minArray);
+ maxAlloc.copyTo(maxArray);
+ for (int i = 0; i < size; i++) {
+ double minValue = Float16Utils.convertFloat16ToDouble(minArray[i]);
+ double maxValue = Float16Utils.convertFloat16ToDouble(maxArray[i]);
+ if (minValue > maxValue) {
+ short temp = minArray[i];
+ minArray[i] = maxArray[i];
+ maxArray[i] = temp;
+ }
+ }
+ minAlloc.copyFrom(minArray);
+ maxAlloc.copyFrom(maxArray);
} else if (dataType == Element.DataType.SIGNED_64) {
long[] minArray = new long[size];
long[] maxArray = new long[size];
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.java
index 8f9b5e4..7499b77 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.java
@@ -5714,6 +5714,688 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalfHalfHalf {
+ public short inValue;
+ public double inValueDouble;
+ public short inMinValue;
+ public double inMinValueDouble;
+ public short inMaxValue;
+ public double inMaxValueDouble;
+ public Target.Floaty out;
+ }
+
+ private void checkClampHalfHalfHalfHalf() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x4b82831l, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0xf102f883l, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x825fea89l, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalfHalfHalfHalf(inValue, out);
+ verifyResultsClampHalfHalfHalfHalf(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalfHalfHalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalfHalfHalfHalf(inValue, out);
+ verifyResultsClampHalfHalfHalfHalf(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalfHalfHalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalfHalfHalfHalf(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 1 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 1 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 1 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 1 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 1 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalfHalfHalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkClampHalf2Half2Half2Half2() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0xb1049715l, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x6f2ebd6fl, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x8baf75l, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalf2Half2Half2Half2(inValue, out);
+ verifyResultsClampHalf2Half2Half2Half2(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf2Half2Half2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalf2Half2Half2Half2(inValue, out);
+ verifyResultsClampHalf2Half2Half2Half2(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf2Half2Half2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalf2Half2Half2Half2(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 2 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i * 2 + j];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i * 2 + j];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i * 2 + j];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 2 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 2 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 2 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 2 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalf2Half2Half2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkClampHalf3Half3Half3Half3() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0xa6d9935dl, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x81facac7l, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x1357bccdl, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalf3Half3Half3Half3(inValue, out);
+ verifyResultsClampHalf3Half3Half3Half3(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf3Half3Half3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalf3Half3Half3Half3(inValue, out);
+ verifyResultsClampHalf3Half3Half3Half3(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf3Half3Half3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalf3Half3Half3Half3(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 3 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i * 4 + j];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i * 4 + j];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i * 4 + j];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 4 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalf3Half3Half3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkClampHalf4Half4Half4Half4() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x9cae8fa5l, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x94c6d81fl, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x2623ca25l, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalf4Half4Half4Half4(inValue, out);
+ verifyResultsClampHalf4Half4Half4Half4(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf4Half4Half4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalf4Half4Half4Half4(inValue, out);
+ verifyResultsClampHalf4Half4Half4Half4(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf4Half4Half4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalf4Half4Half4Half4(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i * 4 + j];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i * 4 + j];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i * 4 + j];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 4 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalf4Half4Half4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkClampHalf2HalfHalfHalf2() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x35f68507l, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0xbc3d6b65l, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x4d9a5d6bl, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalf2HalfHalfHalf2(inValue, out);
+ verifyResultsClampHalf2HalfHalfHalf2(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf2HalfHalfHalf2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalf2HalfHalfHalf2(inValue, out);
+ verifyResultsClampHalf2HalfHalfHalf2(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf2HalfHalfHalf2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalf2HalfHalfHalf2(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 2 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i * 2 + j];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 2 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 2 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 2 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 2 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalf2HalfHalfHalf2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkClampHalf3HalfHalfHalf3() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x1f414e1bl, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x41ad19e1l, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0xd30a0be7l, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalf3HalfHalfHalf3(inValue, out);
+ verifyResultsClampHalf3HalfHalfHalf3(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf3HalfHalfHalf3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalf3HalfHalfHalf3(inValue, out);
+ verifyResultsClampHalf3HalfHalfHalf3(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf3HalfHalfHalf3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalf3HalfHalfHalf3(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 3 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i * 4 + j];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 4 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalf3HalfHalfHalf3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkClampHalf4HalfHalfHalf4() {
+ Allocation inValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x88c172fl, false);
+ Allocation inMinValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0xc71cc85dl, false);
+ Allocation inMaxValue = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x5879ba63l, false);
+ enforceOrdering(inMinValue, inMaxValue);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.set_gAllocInMinValue(inMinValue);
+ script.set_gAllocInMaxValue(inMaxValue);
+ script.forEach_testClampHalf4HalfHalfHalf4(inValue, out);
+ verifyResultsClampHalf4HalfHalfHalf4(inValue, inMinValue, inMaxValue, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf4HalfHalfHalf4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.set_gAllocInMinValue(inMinValue);
+ scriptRelaxed.set_gAllocInMaxValue(inMaxValue);
+ scriptRelaxed.forEach_testClampHalf4HalfHalfHalf4(inValue, out);
+ verifyResultsClampHalf4HalfHalfHalf4(inValue, inMinValue, inMaxValue, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testClampHalf4HalfHalfHalf4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsClampHalf4HalfHalfHalf4(Allocation inValue, Allocation inMinValue, Allocation inMaxValue, Allocation out, boolean relaxed) {
+ short[] arrayInValue = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInValue, (short) 42);
+ inValue.copyTo(arrayInValue);
+ short[] arrayInMinValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMinValue, (short) 42);
+ inMinValue.copyTo(arrayInMinValue);
+ short[] arrayInMaxValue = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInMaxValue, (short) 42);
+ inMaxValue.copyTo(arrayInMaxValue);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalfHalfHalf args = new ArgumentsHalfHalfHalfHalf();
+ args.inValue = arrayInValue[i * 4 + j];
+ args.inValueDouble = Float16Utils.convertFloat16ToDouble(args.inValue);
+ args.inMinValue = arrayInMinValue[i];
+ args.inMinValueDouble = Float16Utils.convertFloat16ToDouble(args.inMinValue);
+ args.inMaxValue = arrayInMaxValue[i];
+ args.inMaxValueDouble = Float16Utils.convertFloat16ToDouble(args.inMaxValue);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeClamp(args, target);
+ // Validate the outputs.
+ boolean valid = true;
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ valid = false;
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inValue: ");
+ appendVariableToMessage(message, args.inValue);
+ message.append("\n");
+ message.append("Input inMinValue: ");
+ appendVariableToMessage(message, args.inMinValue);
+ message.append("\n");
+ message.append("Input inMaxValue: ");
+ appendVariableToMessage(message, args.inMaxValue);
+ message.append("\n");
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("Actual output out: ");
+ appendVariableToMessage(message, arrayOut[i * 4 + j]);
+ message.append("\n");
+ message.append("Actual output out (in double): ");
+ appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]));
+ if (!args.out.couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ message.append(" FAIL");
+ }
+ message.append("\n");
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkClampHalf4HalfHalfHalf4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testClamp() {
checkClampFloatFloatFloatFloat();
checkClampFloat2Float2Float2Float2();
@@ -5778,5 +6460,12 @@
checkClampUlong2UlongUlongUlong2();
checkClampUlong3UlongUlongUlong3();
checkClampUlong4UlongUlongUlong4();
+ checkClampHalfHalfHalfHalf();
+ checkClampHalf2Half2Half2Half2();
+ checkClampHalf3Half3Half3Half3();
+ checkClampHalf4Half4Half4Half4();
+ checkClampHalf2HalfHalfHalf2();
+ checkClampHalf3HalfHalfHalf3();
+ checkClampHalf4HalfHalfHalf4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.rs
index c5a5159..808c27c 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestClamp.rs
@@ -399,3 +399,45 @@
ulong inMaxValue = rsGetElementAt_ulong(gAllocInMaxValue, x);
return clamp(inValue, inMinValue, inMaxValue);
}
+
+half __attribute__((kernel)) testClampHalfHalfHalfHalf(half inValue, unsigned int x) {
+ half inMinValue = rsGetElementAt_half(gAllocInMinValue, x);
+ half inMaxValue = rsGetElementAt_half(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
+
+half2 __attribute__((kernel)) testClampHalf2Half2Half2Half2(half2 inValue, unsigned int x) {
+ half2 inMinValue = rsGetElementAt_half2(gAllocInMinValue, x);
+ half2 inMaxValue = rsGetElementAt_half2(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
+
+half3 __attribute__((kernel)) testClampHalf3Half3Half3Half3(half3 inValue, unsigned int x) {
+ half3 inMinValue = rsGetElementAt_half3(gAllocInMinValue, x);
+ half3 inMaxValue = rsGetElementAt_half3(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
+
+half4 __attribute__((kernel)) testClampHalf4Half4Half4Half4(half4 inValue, unsigned int x) {
+ half4 inMinValue = rsGetElementAt_half4(gAllocInMinValue, x);
+ half4 inMaxValue = rsGetElementAt_half4(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
+
+half2 __attribute__((kernel)) testClampHalf2HalfHalfHalf2(half2 inValue, unsigned int x) {
+ half inMinValue = rsGetElementAt_half(gAllocInMinValue, x);
+ half inMaxValue = rsGetElementAt_half(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
+
+half3 __attribute__((kernel)) testClampHalf3HalfHalfHalf3(half3 inValue, unsigned int x) {
+ half inMinValue = rsGetElementAt_half(gAllocInMinValue, x);
+ half inMaxValue = rsGetElementAt_half(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
+
+half4 __attribute__((kernel)) testClampHalf4HalfHalfHalf4(half4 inValue, unsigned int x) {
+ half inMinValue = rsGetElementAt_half(gAllocInMinValue, x);
+ half inMaxValue = rsGetElementAt_half(gAllocInMaxValue, x);
+ return clamp(inValue, inMinValue, inMaxValue);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java
index edae2df..3b4412b 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java
@@ -318,10 +318,293 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalf {
+ public short inV;
+ public double inVDouble;
+ public short out;
+ public double outDouble;
+ }
+
+ private void checkNativeExpm1HalfHalf() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x1f7c28dl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.forEach_testNativeExpm1HalfHalf(inV, out);
+ verifyResultsNativeExpm1HalfHalf(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1HalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeExpm1HalfHalf(inV, out);
+ verifyResultsNativeExpm1HalfHalf(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1HalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeExpm1HalfHalf(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 1 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 1 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeExpm1HalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeExpm1Half2Half2() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0xddb33a87l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.forEach_testNativeExpm1Half2Half2(inV, out);
+ verifyResultsNativeExpm1Half2Half2(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeExpm1Half2Half2(inV, out);
+ verifyResultsNativeExpm1Half2Half2(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeExpm1Half2Half2(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 2 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 2 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 2 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeExpm1Half2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeExpm1Half3Half3() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x3cbaff7bl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.forEach_testNativeExpm1Half3Half3(inV, out);
+ verifyResultsNativeExpm1Half3Half3(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeExpm1Half3Half3(inV, out);
+ verifyResultsNativeExpm1Half3Half3(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeExpm1Half3Half3(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 3 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 4 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 4 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeExpm1Half3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeExpm1Half4Half4() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x9bc2c46fl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.forEach_testNativeExpm1Half4Half4(inV, out);
+ verifyResultsNativeExpm1Half4Half4(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeExpm1Half4Half4(inV, out);
+ verifyResultsNativeExpm1Half4Half4(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeExpm1Half4Half4(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 4 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 4 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeExpm1Half4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testNativeExpm1() {
checkNativeExpm1FloatFloat();
checkNativeExpm1Float2Float2();
checkNativeExpm1Float3Float3();
checkNativeExpm1Float4Float4();
+ checkNativeExpm1HalfHalf();
+ checkNativeExpm1Half2Half2();
+ checkNativeExpm1Half3Half3();
+ checkNativeExpm1Half4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs
index 2cfee07..a965138 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs
@@ -35,3 +35,19 @@
float4 __attribute__((kernel)) testNativeExpm1Float4Float4(float4 inV) {
return native_expm1(inV);
}
+
+half __attribute__((kernel)) testNativeExpm1HalfHalf(half inV) {
+ return native_expm1(inV);
+}
+
+half2 __attribute__((kernel)) testNativeExpm1Half2Half2(half2 inV) {
+ return native_expm1(inV);
+}
+
+half3 __attribute__((kernel)) testNativeExpm1Half3Half3(half3 inV) {
+ return native_expm1(inV);
+}
+
+half4 __attribute__((kernel)) testNativeExpm1Half4Half4(half4 inV) {
+ return native_expm1(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java
index c6c32b6..b43ff71 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java
@@ -318,10 +318,293 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalf {
+ public short inV;
+ public double inVDouble;
+ public short out;
+ public double outDouble;
+ }
+
+ private void checkNativeTanHalfHalf() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x3e70ec45l, -314, 314);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.forEach_testNativeTanHalfHalf(inV, out);
+ verifyResultsNativeTanHalfHalf(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanHalfHalf(inV, out);
+ verifyResultsNativeTanHalfHalf(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanHalfHalf(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 1 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 1 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanHalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeTanHalf2Half2() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 2, 0xa4d18c7fl, -314, 314);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.forEach_testNativeTanHalf2Half2(inV, out);
+ verifyResultsNativeTanHalf2Half2(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanHalf2Half2(inV, out);
+ verifyResultsNativeTanHalf2Half2(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanHalf2Half2(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 2 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 2 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 2 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanHalf2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeTanHalf3Half3() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x3d95173l, -314, 314);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.forEach_testNativeTanHalf3Half3(inV, out);
+ verifyResultsNativeTanHalf3Half3(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanHalf3Half3(inV, out);
+ verifyResultsNativeTanHalf3Half3(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanHalf3Half3(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 3 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 4 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 4 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanHalf3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeTanHalf4Half4() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x62e11667l, -314, 314);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.forEach_testNativeTanHalf4Half4(inV, out);
+ verifyResultsNativeTanHalf4Half4(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanHalf4Half4(inV, out);
+ verifyResultsNativeTanHalf4Half4(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanHalf4Half4(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 4 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 4 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanHalf4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testNativeTan() {
checkNativeTanFloatFloat();
checkNativeTanFloat2Float2();
checkNativeTanFloat3Float3();
checkNativeTanFloat4Float4();
+ checkNativeTanHalfHalf();
+ checkNativeTanHalf2Half2();
+ checkNativeTanHalf3Half3();
+ checkNativeTanHalf4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs
index cbe930b..f28a852 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs
@@ -35,3 +35,19 @@
float4 __attribute__((kernel)) testNativeTanFloat4Float4(float4 inV) {
return native_tan(inV);
}
+
+half __attribute__((kernel)) testNativeTanHalfHalf(half inV) {
+ return native_tan(inV);
+}
+
+half2 __attribute__((kernel)) testNativeTanHalf2Half2(half2 inV) {
+ return native_tan(inV);
+}
+
+half3 __attribute__((kernel)) testNativeTanHalf3Half3(half3 inV) {
+ return native_tan(inV);
+}
+
+half4 __attribute__((kernel)) testNativeTanHalf4Half4(half4 inV) {
+ return native_tan(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java
index 90afaa9..4104851 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java
@@ -318,10 +318,293 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalf {
+ public short inV;
+ public double inVDouble;
+ public short out;
+ public double outDouble;
+ }
+
+ private void checkNativeTanpiHalfHalf() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 1, 0xa1618990l, -100, 100);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.forEach_testNativeTanpiHalfHalf(inV, out);
+ verifyResultsNativeTanpiHalfHalf(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanpiHalfHalf(inV, out);
+ verifyResultsNativeTanpiHalfHalf(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanpiHalfHalf(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 1];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 1 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 1 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanpiHalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeTanpiHalf2Half2() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x40b19f32l, -100, 100);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.forEach_testNativeTanpiHalf2Half2(inV, out);
+ verifyResultsNativeTanpiHalf2Half2(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanpiHalf2Half2(inV, out);
+ verifyResultsNativeTanpiHalf2Half2(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanpiHalf2Half2(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 2];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 2 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 2 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 2 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanpiHalf2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeTanpiHalf3Half3() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x9fb96426l, -100, 100);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.forEach_testNativeTanpiHalf3Half3(inV, out);
+ verifyResultsNativeTanpiHalf3Half3(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanpiHalf3Half3(inV, out);
+ verifyResultsNativeTanpiHalf3Half3(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanpiHalf3Half3(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 3 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 4 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 4 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanpiHalf3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkNativeTanpiHalf4Half4() {
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xfec1291al, -100, 100);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.forEach_testNativeTanpiHalf4Half4(inV, out);
+ verifyResultsNativeTanpiHalf4Half4(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.forEach_testNativeTanpiHalf4Half4(inV, out);
+ verifyResultsNativeTanpiHalf4Half4(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsNativeTanpiHalf4Half4(Allocation inV, Allocation out, boolean relaxed) {
+ short[] arrayInV = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInV, (short) 42);
+ inV.copyTo(arrayInV);
+ short[] arrayOut = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayOut, (short) 42);
+ out.copyTo(arrayOut);
+ StringBuilder message = new StringBuilder();
+ boolean errorFound = false;
+ for (int i = 0; i < INPUTSIZE; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ // Extract the inputs.
+ ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+ args.inV = arrayInV[i * 4 + j];
+ args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+ // Extract the outputs.
+ args.out = arrayOut[i * 4 + j];
+ args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+ // Ask the CoreMathVerifier to validate.
+ Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+ String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+ boolean valid = errorMessage == null;
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ message.append("Input inV: ");
+ appendVariableToMessage(message, args.inV);
+ message.append("\n");
+ message.append("Output out: ");
+ appendVariableToMessage(message, args.out);
+ message.append("\n");
+ message.append("\n");
+ message.append("Output out (in double): ");
+ appendVariableToMessage(message, args.outDouble);
+ message.append("\n");
+ message.append(errorMessage);
+ message.append("Errors at");
+ }
+ message.append(" [");
+ message.append(Integer.toString(i));
+ message.append(", ");
+ message.append(Integer.toString(j));
+ message.append("]");
+ }
+ }
+ }
+ assertFalse("Incorrect output for checkNativeTanpiHalf4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testNativeTanpi() {
checkNativeTanpiFloatFloat();
checkNativeTanpiFloat2Float2();
checkNativeTanpiFloat3Float3();
checkNativeTanpiFloat4Float4();
+ checkNativeTanpiHalfHalf();
+ checkNativeTanpiHalf2Half2();
+ checkNativeTanpiHalf3Half3();
+ checkNativeTanpiHalf4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs
index 21e0b15..902cda2 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs
@@ -35,3 +35,19 @@
float4 __attribute__((kernel)) testNativeTanpiFloat4Float4(float4 inV) {
return native_tanpi(inV);
}
+
+half __attribute__((kernel)) testNativeTanpiHalfHalf(half inV) {
+ return native_tanpi(inV);
+}
+
+half2 __attribute__((kernel)) testNativeTanpiHalf2Half2(half2 inV) {
+ return native_tanpi(inV);
+}
+
+half3 __attribute__((kernel)) testNativeTanpiHalf3Half3(half3 inV) {
+ return native_tanpi(inV);
+}
+
+half4 __attribute__((kernel)) testNativeTanpiHalf4Half4(half4 inV) {
+ return native_tanpi(inV);
+}
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 5bd88be..6d728da 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -51,7 +51,8 @@
libsync \
libcamera_metadata \
libspeexresampler \
- liblzma
+ liblzma \
+ libstagefright_foundation
LOCAL_SRC_FILES := $(call all-java-files-under, src)\
src/android/security/cts/activity/ISecureRandomService.aidl
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index a8f4382..d39ac7e 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -26,23 +26,16 @@
android_security_cts_CharDeviceTest.cpp \
android_security_cts_KernelSettingsTest.cpp \
android_security_cts_LinuxRngTest.cpp \
- android_security_cts_LoadEffectLibraryTest.cpp \
android_security_cts_NativeCodeTest.cpp \
android_security_cts_SELinuxTest.cpp \
android_security_cts_MMapExecutableTest.cpp \
- android_security_cts_AudioPolicyBinderTest.cpp \
android_security_cts_EncryptionTest.cpp \
- android_security_cts_AudioFlingerBinderTest.cpp \
- android_security_cts_AudioEffectBinderTest.cpp \
- android_security_cts_MediaPlayerInfoLeakTest.cpp \
- android_security_cts_GraphicBufferInfoLeakTest.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
$(TOP)/frameworks/native/include/media/openmax
LOCAL_SHARED_LIBRARIES := libnativehelper \
liblog \
- libbinder \
libutils \
libmedia \
libselinux \
@@ -67,7 +60,8 @@
libsync \
libcamera_metadata \
libspeexresampler \
- liblzma
+ liblzma \
+ libstagefright_foundation
LOCAL_C_INCLUDES += ndk/sources/cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 24c87b1..198baa00 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -21,15 +21,9 @@
extern int register_android_security_cts_CharDeviceTest(JNIEnv*);
extern int register_android_security_cts_LinuxRngTest(JNIEnv*);
extern int register_android_security_cts_NativeCodeTest(JNIEnv*);
-extern int register_android_security_cts_LoadEffectLibraryTest(JNIEnv*);
extern int register_android_security_cts_SELinuxTest(JNIEnv*);
extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
-extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
-extern int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env);
extern int register_android_security_cts_EncryptionTest(JNIEnv* env);
-extern int register_android_security_cts_AudioEffectBinderTest(JNIEnv* env);
-extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
-extern int register_android_security_cts_GraphicBufferInfoLeakTest(JNIEnv* env);
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
@@ -50,10 +44,6 @@
return JNI_ERR;
}
- if (register_android_security_cts_LoadEffectLibraryTest(env)) {
- return JNI_ERR;
- }
-
if (register_android_security_cts_SELinuxTest(env)) {
return JNI_ERR;
}
@@ -66,33 +56,9 @@
return JNI_ERR;
}
- if (register_android_security_cts_AudioPolicyBinderTest(env)) {
- return JNI_ERR;
- }
-
if (register_android_security_cts_EncryptionTest(env)) {
return JNI_ERR;
}
- if (register_android_security_cts_AudioFlingerBinderTest(env)) {
- return JNI_ERR;
- }
-
- if (register_android_security_cts_AudioEffectBinderTest(env)) {
- return JNI_ERR;
- }
-
- if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
- return JNI_ERR;
- }
-
- if (register_android_security_cts_AudioFlingerBinderTest(env)) {
- return JNI_ERR;
- }
-
- if (register_android_security_cts_GraphicBufferInfoLeakTest(env)) {
- return JNI_ERR;
- }
-
return JNI_VERSION_1_4;
}
diff --git a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
deleted file mode 100644
index 6e94fce..0000000
--- a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AudioEffectBinderTest-JNI"
-
-#include <jni.h>
-#include <media/AudioEffect.h>
-#include <media/IEffect.h>
-
-using namespace android;
-
-/*
- * Native methods used by
- * cts/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
- */
-
-struct EffectClient : public BnEffectClient {
- EffectClient() { }
- virtual void controlStatusChanged(bool controlGranted __unused) { }
- virtual void enableStatusChanged(bool enabled __unused) { }
- virtual void commandExecuted(uint32_t cmdCode __unused,
- uint32_t cmdSize __unused,
- void *pCmdData __unused,
- uint32_t replySize __unused,
- void *pReplyData __unused) { }
-};
-
-struct DeathRecipient : public IBinder::DeathRecipient {
- DeathRecipient() : mDied(false) { }
- virtual void binderDied(const wp<IBinder>& who __unused) { mDied = true; }
- bool died() const { return mDied; }
- bool mDied;
-};
-
-static bool isIEffectCommandSecure(IEffect *effect)
-{
- // some magic constants here
- const int COMMAND_SIZE = 1024 + 12; // different than reply size to get different heap frag
- char cmdData[COMMAND_SIZE];
- memset(cmdData, 0xde, sizeof(cmdData));
-
- const int REPLY_DATA_SIZE = 256;
- char replyData[REPLY_DATA_SIZE];
- bool secure = true;
- for (int k = 0; k < 10; ++k) {
- Parcel data;
- data.writeInterfaceToken(effect->getInterfaceDescriptor());
- data.writeInt32(0); // 0 is EFFECT_CMD_INIT
- data.writeInt32(sizeof(cmdData));
- data.write(cmdData, sizeof(cmdData));
- data.writeInt32(sizeof(replyData));
-
- Parcel reply;
- status_t status = effect->asBinder(effect)->transact(3, data, &reply); // 3 is COMMAND
- ALOGV("transact status: %d", status);
- if (status != NO_ERROR) {
- ALOGW("invalid transaction status %d", status);
- continue;
- }
-
- ALOGV("reply data avail %zu", reply.dataAvail());
- status = reply.readInt32();
- ALOGV("reply status %d", status);
- if (status == NO_ERROR) {
- continue;
- }
-
- int size = reply.readInt32();
- ALOGV("reply size %d", size);
- if (size != sizeof(replyData)) { // we expect 0 or full reply data if command failed
- ALOGW_IF(size != 0, "invalid reply size: %d", size);
- continue;
- }
-
- // Note that if reply.read() returns success, it should completely fill replyData.
- status = reply.read(replyData, sizeof(replyData));
- if (status != NO_ERROR) {
- ALOGW("invalid reply read - ignoring");
- continue;
- }
- unsigned int *out = (unsigned int *)replyData;
- for (size_t index = 0; index < sizeof(replyData) / sizeof(*out); ++index) {
- if (out[index] != 0) {
- secure = false;
- ALOGI("leaked data = %#08x", out[index]);
- }
- }
- }
- ALOGI("secure: %s", secure ? "YES" : "NO");
- return secure;
-}
-
-static jboolean android_security_cts_AudioEffect_test_isCommandSecure()
-{
- const sp<IAudioFlinger> &audioFlinger = AudioSystem::get_audio_flinger();
- if (audioFlinger.get() == NULL) {
- ALOGE("could not get audioflinger");
- return JNI_FALSE;
- }
-
- static const effect_uuid_t EFFECT_UIID_EQUALIZER = // type
- { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }};
- sp<EffectClient> effectClient(new EffectClient());
- effect_descriptor_t descriptor;
- memset(&descriptor, 0, sizeof(descriptor));
- descriptor.type = EFFECT_UIID_EQUALIZER;
- descriptor.uuid = *EFFECT_UUID_NULL;
- const int32_t priority = 0;
- const audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX;
- const audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
- const String16 opPackageName("Exploitable");
- status_t status;
- int32_t id;
- int enabled;
- sp<IEffect> effect = audioFlinger->createEffect(&descriptor, effectClient,
- priority, io, sessionId, opPackageName, &status, &id, &enabled);
- if (effect.get() == NULL || status != NO_ERROR) {
- ALOGW("could not create effect");
- return JNI_TRUE;
- }
-
- sp<DeathRecipient> deathRecipient(new DeathRecipient());
- IInterface::asBinder(effect)->linkToDeath(deathRecipient);
-
- // check exploit
- if (!isIEffectCommandSecure(effect.get())) {
- ALOGE("not secure!");
- return JNI_FALSE;
- }
-
- sleep(1); // wait to check death
- if (deathRecipient->died()) {
- ALOGE("effect binder died");
- return JNI_FALSE;
- }
- return JNI_TRUE;
-}
-
-int register_android_security_cts_AudioEffectBinderTest(JNIEnv *env)
-{
- static JNINativeMethod methods[] = {
- { "native_test_isCommandSecure", "()Z",
- (void *) android_security_cts_AudioEffect_test_isCommandSecure },
- };
-
- jclass clazz = env->FindClass("android/security/cts/AudioEffectBinderTest");
- return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
-}
diff --git a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
deleted file mode 100644
index f4e79e5..0000000
--- a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AudioFlingerBinderTest-JNI"
-
-#include <jni.h>
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <media/IAudioFlinger.h>
-#include <media/AudioSystem.h>
-#include <system/audio.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-
-using namespace android;
-
-/*
- * Native methods used by
- * cts/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
- */
-
-#define TEST_ARRAY_SIZE 10000
-#define MAX_ARRAY_SIZE 1024
-#define TEST_PATTERN 0x55
-
-class MyDeathClient: public IBinder::DeathRecipient
-{
-public:
- MyDeathClient() :
- mAfIsDead(false) {
- }
-
- bool afIsDead() const { return mAfIsDead; }
-
- // DeathRecipient
- virtual void binderDied(const wp<IBinder>& who __unused) { mAfIsDead = true; }
-
-private:
- bool mAfIsDead;
-};
-
-
-static bool connectAudioFlinger(sp<IAudioFlinger>& af, sp<MyDeathClient> &dr)
-{
- int64_t startTime = 0;
- while (af == 0) {
- sp<IBinder> binder = defaultServiceManager()->checkService(String16("media.audio_flinger"));
- if (binder == 0) {
- if (startTime == 0) {
- startTime = uptimeMillis();
- } else if ((uptimeMillis()-startTime) > 10000) {
- ALOGE("timeout while getting audio flinger service");
- return false;
- }
- sleep(1);
- } else {
- af = interface_cast<IAudioFlinger>(binder);
- dr = new MyDeathClient();
- binder->linkToDeath(dr);
- }
- }
- // Allow binderDied() to be called on MyDeathClient
- sp<ProcessState> proc(ProcessState::self());
- ProcessState::self()->startThreadPool();
- return true;
-}
-
-/*
- * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
- * is opened.
- */
-jboolean android_security_cts_AudioFlinger_test_setMasterMute(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- // force opening of a duplicating output
- status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- "0", "");
- if (status != NO_ERROR) {
- return false;
- }
-
- bool mute;
- status = AudioSystem::getMasterMute(&mute);
- if (status != NO_ERROR) {
- return false;
- }
-
- AudioSystem::setMasterMute(!mute);
-
- sleep(1);
-
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
-
- AudioSystem::setMasterMute(mute);
-
- AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- "0", "");
-
- AudioSystem::setMasterMute(false);
-
- return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_setMasterVolume(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- // force opening of a duplicating output
- status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- "0", "");
- if (status != NO_ERROR) {
- return false;
- }
-
- float vol;
- status = AudioSystem::getMasterVolume(&vol);
- if (status != NO_ERROR) {
- return false;
- }
-
- AudioSystem::setMasterVolume(vol < 0.5 ? 1.0 : 0.0);
-
- sleep(1);
-
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
-
- AudioSystem::setMasterMute(vol);
-
- AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- "0", "");
-
- return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_listAudioPorts(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- unsigned int num_ports = TEST_ARRAY_SIZE;
- struct audio_port *ports =
- (struct audio_port *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_port));
-
- memset(ports, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_port));
-
- status_t status = af->listAudioPorts(&num_ports, ports);
-
- sleep(1);
-
- // Check that the memory content above the max allowed array size was not changed
- char *ptr = (char *)(ports + MAX_ARRAY_SIZE);
- for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
- if (ptr[i * sizeof(struct audio_port)] != TEST_PATTERN) {
- free(ports);
- return false;
- }
- }
-
- free(ports);
-
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
-
- return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_listAudioPatches(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- unsigned int num_patches = TEST_ARRAY_SIZE;
- struct audio_patch *patches =
- (struct audio_patch *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_patch));
-
- memset(patches, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_patch));
-
- status_t status = af->listAudioPatches(&num_patches, patches);
-
- sleep(1);
-
- // Check that the memory content above the max allowed array size was not changed
- char *ptr = (char *)(patches + MAX_ARRAY_SIZE);
- for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
- if (ptr[i * sizeof(struct audio_patch)] != TEST_PATTERN) {
- free(patches);
- return false;
- }
- }
-
- free(patches);
-
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
-
- return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_createEffect(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- for (int j = 0; j < 10; ++j) {
- Parcel data, reply;
- data.writeInterfaceToken(af->getInterfaceDescriptor());
- data.writeInt32((int32_t)j);
- status_t status = af->asBinder(af)->transact(40, data, &reply); // 40 is CREATE_EFFECT
- if (status != NO_ERROR) {
- return false;
- }
-
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- continue;
- }
-
- int id = reply.readInt32();
- int enabled = reply.readInt32();
- sp<IEffect> effect = interface_cast<IEffect>(reply.readStrongBinder());
- effect_descriptor_t desc;
- effect_descriptor_t descTarget;
- memset(&desc, 0, sizeof(effect_descriptor_t));
- memset(&descTarget, 0, sizeof(effect_descriptor_t));
- reply.read(&desc, sizeof(effect_descriptor_t));
- if (id != 0 || enabled != 0 || memcmp(&desc, &descTarget, sizeof(effect_descriptor_t))) {
- return false;
- }
- }
-
- sleep(1);
-
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
-
- return true;
-}
-
-
-#define NUM_ATTEMPTS 5
-
-jboolean android_security_cts_AudioFlinger_test_getInputBufferSize(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- for (size_t i = 0; i < NUM_ATTEMPTS; i++) {
- af->getInputBufferSize(0, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO);
- sleep(1);
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
- }
-
- return true;
-}
-
-static JNINativeMethod gMethods[] = {
- { "native_test_setMasterMute", "()Z",
- (void *) android_security_cts_AudioFlinger_test_setMasterMute },
- { "native_test_setMasterVolume", "()Z",
- (void *) android_security_cts_AudioFlinger_test_setMasterVolume },
- { "native_test_listAudioPorts", "()Z",
- (void *) android_security_cts_AudioFlinger_test_listAudioPorts },
- { "native_test_listAudioPatches", "()Z",
- (void *) android_security_cts_AudioFlinger_test_listAudioPatches },
- { "native_test_createEffect", "()Z",
- (void *) android_security_cts_AudioFlinger_test_createEffect },
- { "native_test_getInputBufferSize", "()Z",
- (void *) android_security_cts_AudioFlinger_test_getInputBufferSize },
-};
-
-int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env)
-{
- jclass clazz = env->FindClass("android/security/cts/AudioFlingerBinderTest");
- return env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
deleted file mode 100644
index d0a8ec9..0000000
--- a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
+++ /dev/null
@@ -1,268 +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.
- */
-
-#define LOG_TAG "AudioPolicyBinderTest-JNI"
-
-#include <jni.h>
-#include <binder/IServiceManager.h>
-#include <binder/Parcel.h>
-#include <media/IAudioPolicyService.h>
-#include <media/AudioSystem.h>
-#include <system/audio.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-
-using namespace android;
-
-/*
- * Native methods used by
- * cts/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
- */
-
-static bool init(sp<IAudioPolicyService>& aps, audio_io_handle_t *output, int *session)
-{
- aps = 0;
- if (output != NULL) {
- *output = AUDIO_IO_HANDLE_NONE;
- }
- if (session != NULL) {
- *session = AUDIO_UNIQUE_ID_ALLOCATE;
- }
-
- int64_t startTime = 0;
- sp<IServiceManager> sm = defaultServiceManager();
- while (aps == 0) {
- sp<IBinder> binder = defaultServiceManager()->checkService(String16("media.audio_policy"));
- if (binder == 0) {
- if (startTime == 0) {
- startTime = uptimeMillis();
- } else if ((uptimeMillis()-startTime) > 10000) {
- ALOGE("timeout while getting audio policy service");
- return false;
- }
- sleep(1);
- } else {
- aps = interface_cast<IAudioPolicyService>(binder);
- }
- }
-
- if (output != NULL) {
- // get a valid output. Any use case will do.
- for (int stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT; stream++) {
- *output = AudioSystem::getOutput((audio_stream_type_t)stream);
- if (*output != AUDIO_IO_HANDLE_NONE) {
- break;
- }
- }
- if (*output == AUDIO_IO_HANDLE_NONE) {
- ALOGE("cannot get valid audio output");
- return false;
- }
- }
- if (session != NULL) {
- //get a valid session
- *session = AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
- if (*session == AUDIO_UNIQUE_ID_ALLOCATE) {
- ALOGE("cannot get valid audio session");
- return false;
- }
- }
- return true;
-}
-
-/*
- * Checks that IAudioPolicyService::startOutput() cannot be called with an
- * invalid stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_startOutput(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioPolicyService> aps;
- audio_io_handle_t output;
- int session;
-
- if (!init(aps, &output, &session)) {
- return false;
- }
-
- status_t status = aps->startOutput(output, (audio_stream_type_t)(AUDIO_STREAM_MIN -1),
- (audio_session_t)session);
- if (status == NO_ERROR) {
- return false;
- }
- status = aps->startOutput(output, (audio_stream_type_t)AUDIO_STREAM_CNT,
- (audio_session_t)session);
- if (status == NO_ERROR) {
- return false;
- }
- return true;
-}
-
-/*
- * Checks that IAudioPolicyService::stopOutput() cannot be called with an
- * invalid stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_stopOutput(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioPolicyService> aps;
- audio_io_handle_t output;
- int session;
-
- if (!init(aps, &output, &session)) {
- return false;
- }
-
- status_t status = aps->stopOutput(output, (audio_stream_type_t)(AUDIO_STREAM_MIN -1),
- (audio_session_t)session);
- if (status == NO_ERROR) {
- return false;
- }
- status = aps->stopOutput(output, (audio_stream_type_t)AUDIO_STREAM_CNT,
- (audio_session_t)session);
- if (status == NO_ERROR) {
- return false;
- }
- return true;
-}
-
-/*
- * Checks that IAudioPolicyService::isStreamActive() cannot be called with an
- * invalid stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_isStreamActive(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioPolicyService> aps;
-
- if (!init(aps, NULL, NULL)) {
- return false;
- }
-
- bool status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
- if (status) {
- return false;
- }
- status = aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0);
- if (status) {
- return false;
- }
- return true;
-}
-
-/*
- * Checks that IAudioPolicyService::isStreamActiveRemotely() cannot be called with an
- * invalid stream type.
- * Test with NUM_RANDOM_TESTS random values for stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_isStreamActiveRemotely(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioPolicyService> aps;
-
- if (!init(aps, NULL, NULL)) {
- return false;
- }
-
- if (aps->isStreamActiveRemotely((audio_stream_type_t)(AUDIO_STREAM_MIN -1), 0)) {
- return false;
- }
-
- if (aps->isStreamActiveRemotely((audio_stream_type_t)AUDIO_STREAM_CNT, 0)) {
- return false;
- }
- return true;
-}
-
-jint android_security_cts_AudioPolicy_test_getStreamVolumeLeak(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioPolicyService> aps;
-
- if (!init(aps, NULL, NULL)) {
- return -1;
- }
-
- // Keep synchronized with IAudioPolicyService.cpp!
- enum {
- GET_STREAM_VOLUME = 17,
- };
-
- Parcel data, reply;
- status_t err;
- data.writeInterfaceToken(aps->getInterfaceDescriptor());
- data.writeInt32(-1); // stream type
- data.writeInt32(-1); // device
- IInterface::asBinder(aps)->transact(GET_STREAM_VOLUME, data, &reply);
- int index = reply.readInt32();
- err = reply.readInt32();
-
- return index;
-}
-
-jboolean android_security_cts_AudioPolicy_test_startAudioSource(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioPolicyService> aps;
-
- if (!init(aps, NULL, NULL)) {
- return false;
- }
-
- // Keep synchronized with IAudioPolicyService.cpp!
- enum {
- START_AUDIO_SOURCE = 41,
- };
-
- for (int i = 0; i < 10; ++i) {
- Parcel data, reply;
- data.writeInterfaceToken(aps->getInterfaceDescriptor());
- data.writeInt32(-i);
- IInterface::asBinder(aps)->transact(START_AUDIO_SOURCE, data, &reply);
- status_t err = (status_t)reply.readInt32();
- if (err == NO_ERROR) {
- continue;
- }
- audio_io_handle_t handle = (audio_io_handle_t)reply.readInt32();
- if (handle != 0) {
- return false;
- }
- }
-
- return true;
-}
-
-static JNINativeMethod gMethods[] = {
- { "native_test_startOutput", "()Z",
- (void *) android_security_cts_AudioPolicy_test_startOutput },
- { "native_test_stopOutput", "()Z",
- (void *) android_security_cts_AudioPolicy_test_stopOutput },
- { "native_test_isStreamActive", "()Z",
- (void *) android_security_cts_AudioPolicy_test_isStreamActive },
- { "native_test_isStreamActiveRemotely", "()Z",
- (void *) android_security_cts_AudioPolicy_test_isStreamActiveRemotely },
- { "native_test_getStreamVolumeLeak", "()I",
- (void *) android_security_cts_AudioPolicy_test_getStreamVolumeLeak },
- { "native_test_startAudioSource", "()Z",
- (void *) android_security_cts_AudioPolicy_test_startAudioSource },
-};
-
-int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env)
-{
- jclass clazz = env->FindClass("android/security/cts/AudioPolicyBinderTest");
- return env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_GraphicBufferInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_GraphicBufferInfoLeakTest.cpp
deleted file mode 100644
index d0cd347..0000000
--- a/tests/tests/security/jni/android_security_cts_GraphicBufferInfoLeakTest.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "GraphicBufferInfoLeakTest-JNI"
-
-#include <jni.h>
-#include <JNIHelp.h>
-
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IMediaRecorder.h>
-#include <media/IOMX.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include <sys/stat.h>
-#include <fcntl.h>
-
-using namespace android;
-
-static sp<IMediaPlayerService> getMediaPlayerService()
-{
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
-
- sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
- return iMPService;
-}
-
-jint android_security_cts_GraphicBuffer_test_attachBufferInfoLeak(JNIEnv* env,
- jobject thiz __unused)
-{
- sp<IMediaPlayerService> iMPService = getMediaPlayerService();
-
- // get IOMX
- // Keep synchronized with IMediaPlayerService.cpp!
- enum {
- GET_OMX = 4,
- };
-
- status_t err;
- Parcel data, reply;
- data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
- err = IMediaPlayerService::asBinder(iMPService)->transact(GET_OMX, data, &reply);
- if (err != NO_ERROR) {
- jniThrowException(env, "java/lang/RuntimeException", "GET_OMX failed");
- }
-
- // get IGraphicBufferConsumer
- sp<IGraphicBufferProducer> iBufferProducer;
- sp<IGraphicBufferConsumer> iBufferConsumer;
- sp<IOMX> iOmx = interface_cast<IOMX>(reply.readStrongBinder());
- err = iOmx->createPersistentInputSurface(&iBufferProducer, &iBufferConsumer);
- if (err != NO_ERROR) {
- jniThrowException(env, "java/lang/RuntimeException", "createPersistentInputSurface failed");
- return err;
- }
-
- // Keep synchronized with IGraphicBufferConsumer.cpp!
- enum {
- ATTACH_BUFFER = 3,
- };
-
- for (;;) {
- Parcel data2, reply2;
- data2.writeInterfaceToken(iBufferConsumer->getInterfaceDescriptor());
- err = IGraphicBufferConsumer::asBinder(iBufferConsumer)->transact(ATTACH_BUFFER, data2, &reply2);
- if (err != NO_ERROR) {
- jniThrowException(env, "java/lang/RuntimeException", "ATTACH_BUFFER failed");
- }
-
- int32_t slot = reply2.readInt32();
- status_t result = reply2.readInt32();
- ALOGV("slot %d", slot);
- if (result != 0) {
- // only check for leaked data in error case
- return slot;
- }
- }
-}
-
-jint android_security_cts_GraphicBuffer_test_queueBufferInfoLeak(JNIEnv* env,
- jobject thiz __unused)
-{
- sp<IMediaPlayerService> iMPService = getMediaPlayerService();
- sp<IMediaRecorder> recorder = iMPService->createMediaRecorder(String16("GraphicBufferInfoLeakTest"));
-
- const char *fileName = "/dev/null";
- int fd = open(fileName, O_RDWR | O_CREAT, 0744);
- if (fd < 0) {
- jniThrowException(env, "java/lang/RuntimeException", "open output failed");
- return fd;
- }
-
- recorder->setVideoSource(2);
- recorder->setOutputFile(fd, 0, 0);
- recorder->setOutputFormat(0);
- recorder->init();
- recorder->prepare();
- recorder->start();
-
- //get IGraphicBufferProducer
- sp<IGraphicBufferProducer> iGBP = recorder->querySurfaceMediaSource();
- ALOGV("fd %d, Get iGBP instance, 0x%08x\n", fd, iGBP.get());
-
- // Keep synchronized with IGraphicBufferProducer.cpp!
- enum {
- QUEUE_BUFFER = 7,
- };
-
- for (;;) {
- status_t err;
- Parcel data, reply;
- data.writeInterfaceToken(iGBP->getInterfaceDescriptor());
- data.writeInt32(-1);
- err = IGraphicBufferProducer::asBinder(iGBP)->transact(QUEUE_BUFFER, data, &reply);
- if (err != NO_ERROR) {
- recorder->stop();
- recorder->release();
- jniThrowException(env, "java/lang/RuntimeException", "QUEUE_BUFFER failed");
- return err;
- }
-
- size_t len = reply.dataAvail();
- int32_t result; // last sizeof(int32_t) bytes of Parcel
- ALOGV("dataAvail = %zu\n", len);
- if (len < sizeof(result)) {
- // must contain result
- recorder->stop();
- recorder->release();
- jniThrowException(env, "java/lang/RuntimeException", "reply malformed");
- return ERROR_MALFORMED;
- }
-
- uint8_t *reply_data = (uint8_t *)reply.data();
- memcpy(&result, reply_data + len - sizeof(result), sizeof(result));
- if (result == NO_ERROR) {
- // only check for leaked data in error case
- continue;
- }
-
- uint8_t leaked_data = 0;
- for (size_t i = 0; i < len - sizeof(result); ++i) {
- ALOGV("IGraphicBufferProducer_InfoLeak reply_data[%d] = 0x%08x", i, reply_data[i]);
- if (reply_data[i]) {
- leaked_data = reply_data[i];
- break;
- }
- }
-
- recorder->stop();
- recorder->release();
- return leaked_data;
- }
-}
-
-static JNINativeMethod gMethods[] = {
- { "native_test_attachBufferInfoLeak", "()I",
- (void *) android_security_cts_GraphicBuffer_test_attachBufferInfoLeak },
- { "native_test_queueBufferInfoLeak", "()I",
- (void *) android_security_cts_GraphicBuffer_test_queueBufferInfoLeak },
-};
-
-int register_android_security_cts_GraphicBufferInfoLeakTest(JNIEnv* env)
-{
- jclass clazz = env->FindClass("android/security/cts/GraphicBufferInfoLeakTest");
- return env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_LoadEffectLibraryTest.cpp b/tests/tests/security/jni/android_security_cts_LoadEffectLibraryTest.cpp
deleted file mode 100644
index 6e0f6e1..0000000
--- a/tests/tests/security/jni/android_security_cts_LoadEffectLibraryTest.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#include <jni.h>
-#include <binder/IServiceManager.h>
-#include <media/IAudioFlinger.h>
-#include <media/AudioEffect.h>
-
-
-using namespace android;
-
-
-/*
- * Native method used by
- * cts/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java
- *
- * Checks that no IAudioFlinger binder transaction manages to load an effect library
- * as LOAD_EFFECT_LIBRARY did in gingerbread.
- */
-
-jboolean android_security_cts_LoadEffectLibraryTest_doLoadLibraryTest(JNIEnv* env, jobject thiz)
-{
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == 0) {
- return false;
- }
-
- sp<IBinder> binder = sm->getService(String16("media.audio_flinger"));
- if (binder == 0) {
- return false;
- }
-
- Parcel data, reply;
- sp<IAudioFlinger> af = interface_cast<IAudioFlinger>(binder);
-
- data.writeInterfaceToken(af->getInterfaceDescriptor());
- // test library path defined in cts/tests/tests/security/testeffect/Android.mk
- data.writeCString("/system/lib/soundfx/libctstesteffect.so");
-
- // test 100 IAudioFlinger binder transaction values and check that none corresponds
- // to LOAD_EFFECT_LIBRARY and successfully loads our test library
- for (uint32_t i = IBinder::FIRST_CALL_TRANSACTION;
- i < IBinder::FIRST_CALL_TRANSACTION + 100;
- i++) {
- status_t status = binder->transact(i, data, &reply);
- if (status != NO_ERROR) {
- continue;
- }
- status = reply.readInt32();
- if (status != NO_ERROR) {
- continue;
- }
-
- // Effect UUID defined in cts/tests/tests/security/testeffect/CTSTestEffect.cpp
- effect_uuid_t uuid =
- {0xff93e360, 0x0c3c, 0x11e3, 0x8a97, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
- effect_descriptor_t desc;
-
- status = AudioEffect::getEffectDescriptor(&uuid, &desc);
- if (status == NO_ERROR) {
- return false;
- }
- }
- return true;
-}
-
-static JNINativeMethod gMethods[] = {
- { "doLoadLibraryTest", "()Z",
- (void *) android_security_cts_LoadEffectLibraryTest_doLoadLibraryTest },
-};
-
-int register_android_security_cts_LoadEffectLibraryTest(JNIEnv* env)
-{
- jclass clazz = env->FindClass("android/security/cts/LoadEffectLibraryTest");
- return env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
deleted file mode 100644
index 0c61f25..0000000
--- a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaPlayerInfoLeakTest-JNI"
-
-#include <jni.h>
-
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-
-#include <media/IMediaPlayer.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IMediaPlayerClient.h>
-
-#include <sys/stat.h>
-
-using namespace android;
-
-static status_t connectMediaPlayer(sp<IMediaPlayer>& iMP)
-{
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
-
- sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
- sp<IMediaPlayerClient> client;
- Parcel data, reply;
- int dummyAudioSessionId = 1;
- data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(client));
- data.writeInt32(dummyAudioSessionId);
-
- // Keep synchronized with IMediaPlayerService.cpp!
- enum {
- CREATE = IBinder::FIRST_CALL_TRANSACTION,
- };
- status_t err = IInterface::asBinder(iMPService)->transact(CREATE, data, &reply);
- if (err == NO_ERROR) {
- iMP = interface_cast<IMediaPlayer>(reply.readStrongBinder());
- }
- return err;
-}
-
-int testMediaPlayerInfoLeak(int command)
-{
- sp<IMediaPlayer> iMP;
- if (NO_ERROR != connectMediaPlayer(iMP)) {
- return false;
- }
-
-
- Parcel data, reply;
- data.writeInterfaceToken(iMP->getInterfaceDescriptor());
- IInterface::asBinder(iMP)->transact(command, data, &reply);
-
- int leak = reply.readInt32();
- status_t err = reply.readInt32();
- return leak;
-}
-
-jint android_security_cts_MediaPlayer_test_getCurrentPositionLeak(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- // Keep synchronized with IMediaPlayer.cpp!
- enum {
- GET_CURRENT_POSITION = 16,
- };
- return testMediaPlayerInfoLeak(GET_CURRENT_POSITION);
-}
-
-jint android_security_cts_MediaPlayer_test_getDurationLeak(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- // Keep synchronized with IMediaPlayer.cpp!
- enum {
- GET_DURATION = 17,
- };
- return testMediaPlayerInfoLeak(GET_DURATION);
-}
-
-static JNINativeMethod gMethods[] = {
- { "native_test_getCurrentPositionLeak", "()I",
- (void *) android_security_cts_MediaPlayer_test_getCurrentPositionLeak },
- { "native_test_getDurationLeak", "()I",
- (void *) android_security_cts_MediaPlayer_test_getDurationLeak },
-};
-
-int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env)
-{
- jclass clazz = env->FindClass("android/security/cts/MediaPlayerInfoLeakTest");
- return env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java b/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
deleted file mode 100644
index 20d9615..0000000
--- a/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.media.audiofx.AudioEffect;
-
-import java.util.UUID;
-
-import junit.framework.TestCase;
-
-public class AudioEffectBinderTest extends TestCase {
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
- /**
- * Checks that IEffect::command() cannot leak data.
- */
- public void test_isCommandSecure() throws Exception {
- if (isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
- assertTrue(native_test_isCommandSecure());
- }
- }
-
- /* see AudioEffect.isEffectTypeAvailable(), implements hidden function */
- private static boolean isEffectTypeAvailable(UUID type) {
- AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
- if (desc == null) {
- return false;
- }
-
- for (int i = 0; i < desc.length; i++) {
- if (desc[i].type.equals(type)) {
- return true;
- }
- }
- return false;
- }
-
- private static native boolean native_test_isCommandSecure();
-}
diff --git a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
deleted file mode 100644
index e84d851..0000000
--- a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import junit.framework.TestCase;
-
-public class AudioFlingerBinderTest extends TestCase {
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
- /**
- * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
- * is opened.
- */
- public void test_setMasterMute() throws Exception {
- assertTrue(native_test_setMasterMute());
- }
-
- /**
- * Checks that AudioSystem::setMasterVolume() does not crash mediaserver if a duplicated output
- * is opened.
- */
- public void test_setMasterVolume() throws Exception {
- assertTrue(native_test_setMasterVolume());
- }
-
- /**
- * Checks that IAudioFlinger::listAudioPorts() does not cause a memory overflow when passed a
- * large number of ports.
- */
- public void test_listAudioPorts() throws Exception {
- assertTrue(native_test_listAudioPorts());
- }
-
- /**
- * Checks that IAudioFlinger::listAudioPatches() does not cause a memory overflow when passed a
- * large number of ports.
- */
- public void test_listAudioPatches() throws Exception {
- assertTrue(native_test_listAudioPatches());
- }
-
- /**
- * Checks that IAudioFlinger::createEffect() does not leak information on the server side.
- */
- public void test_createEffect() throws Exception {
- assertTrue(native_test_createEffect());
- }
-
- /**
- * Checks that passing a sample rate of 0 to IAudioFlinger::getInputBufferSize()
- * does not cause a crash in audioserver.
- */
- public void test_getInputBufferSize() throws Exception {
- assertTrue(native_test_getInputBufferSize());
- }
-
- private static native boolean native_test_setMasterMute();
- private static native boolean native_test_setMasterVolume();
- private static native boolean native_test_listAudioPorts();
- private static native boolean native_test_listAudioPatches();
- private static native boolean native_test_createEffect();
- private static native boolean native_test_getInputBufferSize();
-}
diff --git a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
deleted file mode 100644
index 82346a1..0000000
--- a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
+++ /dev/null
@@ -1,82 +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 android.security.cts;
-
-import junit.framework.TestCase;
-
-public class AudioPolicyBinderTest extends TestCase {
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
- /**
- * Checks that IAudioPolicyService::startOutput() cannot be called with an
- * invalid stream type.
- */
- public void test_startOutput() throws Exception {
- assertTrue(native_test_startOutput());
- }
-
- /**
- * Checks that IAudioPolicyService::stopOutput() cannot be called with an
- * invalid stream type.
- */
- public void test_stopOutput() throws Exception {
- assertTrue(native_test_stopOutput());
- }
-
- /**
- * Checks that IAudioPolicyService::isStreamActive() cannot be called with an
- * invalid stream type.
- */
- public void test_isStreamActive() throws Exception {
- assertTrue(native_test_isStreamActive());
- }
-
- /**
- * Checks that IAudioPolicyService::isStreamActiveRemotely() cannot be called with an
- * invalid stream type.
- */
- public void test_isStreamActiveRemotely() throws Exception {
- assertTrue(native_test_isStreamActiveRemotely());
- }
-
- /**
- * Checks that IAudioPolicyService::getStreamVolumeIndex() does not leak information
- * when called with an invalid stream/device type.
- */
- public void test_getStreamVolumeLeak() throws Exception {
- int volume = native_test_getStreamVolumeLeak();
- assertTrue(String.format("Leaked volume 0x%08X", volume), volume == 0);
- }
-
- /**
- * Checks that IAudioPolicyService::startAudioSource() cannot leak information from
- * server side.
- */
- public void test_startAudioSource() throws Exception {
- assertTrue(native_test_startAudioSource());
- }
-
- private static native boolean native_test_startOutput();
- private static native boolean native_test_stopOutput();
- private static native boolean native_test_isStreamActive();
- private static native boolean native_test_isStreamActiveRemotely();
- private static native int native_test_getStreamVolumeLeak();
- private static native boolean native_test_startAudioSource();
-}
diff --git a/tests/tests/security/src/android/security/cts/CertificateTest.java b/tests/tests/security/src/android/security/cts/CertificateTest.java
index 3db7aca..5d2a04f 100644
--- a/tests/tests/security/src/android/security/cts/CertificateTest.java
+++ b/tests/tests/security/src/android/security/cts/CertificateTest.java
@@ -16,19 +16,13 @@
package android.security.cts;
-import android.content.res.AssetManager;
-import android.test.InstrumentationTestCase;
-
-import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
@@ -36,7 +30,9 @@
import java.util.List;
import java.util.Set;
-public class CertificateTest extends InstrumentationTestCase {
+import junit.framework.TestCase;
+
+public class CertificateTest extends TestCase {
public void testNoRemovedCertificates() throws Exception {
Set<String> expectedCertificates = new HashSet<String>(
@@ -50,55 +46,25 @@
* If you fail CTS as a result of adding a root CA that is not part of the Android root CA
* store, please see the following.
*
- * First, this test exists because adding untrustworthy root CAs to a device has a very
- * significant security impact. In the worst case, adding a rogue CA can permanently compromise
- * the confidentiality and integrity of your users' network traffic. Because of this risk,
- * adding new certificates should be done sparingly and as a last resort -- never as a first
- * response or short term fix. Before attempting to modify this test, please consider whether
- * adding a new certificate authority is in your users' best interests.
+ * <p>This test exists because adding root CAs to a device has a very significant security
+ * impact. Whoever has access to the signing keys of that CA can compromise secure network
+ * traffic from affected Android devices, putting users at risk.
*
- * Second, because the addition of a new root CA by an OEM can have such dire consequences for
- * so many people it is imperative that it be done transparently and in the open. Any request to
- * modify the certificate list used by this test must have a corresponding change in AOSP
- * (one certificate per change) authored by the OEM in question and including:
+ * <p>If you have a CA certificate which needs to be trusted by a particular app/service,
+ * ask the developer of the app/service to modify it to trust this CA (e.g., using Network
+ * Security Config feature). This avoids compromising the security of network traffic of other
+ * apps on the device.
*
- * - the certificate in question:
- * - The certificate must be in a file under
- * cts/tests/tests/security/assets/oem_cacerts, in PEM (Privacy-enhanced Electronic
- * Mail) format, with the textual representation of the certificate following the PEM
- * section.
- * - The file name must be in the format of <hash>.<n> where "hash" is the subject hash
- * produced by:
- * openssl x509 -in cert_file -subject_hash -noout
- * and the "n" is a unique integer identifier starting at 0 to deal with collisions.
- * See OpenSSL's c_rehash manpage for details.
- * - cts/tests/tests/security/tools/format_cert.sh helps meet the above requirements.
+ * <p>If you have a CA certificate that you believe should be present on all Android devices,
+ * please file a public bug at https://code.google.com/p/android/issues/entry.
*
- * - information about who created and maintains both the certificate and the corresponding
- * keypair.
- *
- * - information about what the certificate is to be used for and why the certificate is
- * appropriate for inclusion.
- *
- * - a statement from the OEM indicating that they have sufficient confidence in the
- * security of the key, the security practices of the issuer, and the validity of the
- * intended use that they believe adding the certificate is not detrimental to the
- * security of the user.
- *
- * Finally, please note that this is not the usual process for adding root CAs to Android. If
- * you have a certificate that you believe should be present on all Android devices, please file
- * a public bug at https://code.google.com/p/android/issues/entry or http://b.android.com to
- * seek resolution.
- *
- * For questions, comments, and code reviews please contact security@android.com.
+ * <p>For questions, comments, and code reviews please contact security@android.com.
*/
public void testNoAddedCertificates() throws Exception {
- Set<String> oemWhitelistedCertificates = getOemWhitelistedCertificates();
Set<String> expectedCertificates = new HashSet<String>(
Arrays.asList(CertificateData.CERTIFICATE_DATA));
Set<String> deviceCertificates = getDeviceCertificates();
deviceCertificates.removeAll(expectedCertificates);
- deviceCertificates.removeAll(oemWhitelistedCertificates);
assertEquals("Unknown CA certificates", Collections.EMPTY_SET, deviceCertificates);
}
@@ -132,30 +98,6 @@
return certificates;
}
- private static final String ASSETS_DIR_OEM_CERTS = "oem_cacerts";
-
- private Set<String> getOemWhitelistedCertificates() throws Exception {
- Set<String> certificates = new HashSet<String>();
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- AssetManager assetManager = getInstrumentation().getContext().getAssets();
- for (String path : assetManager.list(ASSETS_DIR_OEM_CERTS)) {
- File certAssetFile = new File(ASSETS_DIR_OEM_CERTS, path);
- InputStream in = null;
- try {
- in = assetManager.open(certAssetFile.toString());
- X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(in);
- certificates.add(getFingerprint(certificate));
- } catch (Exception e) {
- throw new Exception("Failed to load certificate from asset: " + certAssetFile, e);
- } finally {
- if (in != null) {
- in.close();
- }
- }
- }
- return certificates;
- }
-
private String getFingerprint(X509Certificate certificate) throws CertificateEncodingException,
NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
diff --git a/tests/tests/security/src/android/security/cts/GraphicBufferInfoLeakTest.java b/tests/tests/security/src/android/security/cts/GraphicBufferInfoLeakTest.java
deleted file mode 100644
index 6005e37..0000000
--- a/tests/tests/security/src/android/security/cts/GraphicBufferInfoLeakTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import junit.framework.TestCase;
-
-public class GraphicBufferInfoLeakTest extends TestCase {
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
- /**
- * Check that IGraphicBufferConsumer::attachBuffer does not leak info in error case
- */
- public void test_attachBufferInfoLeak() throws Exception {
- int slot = native_test_attachBufferInfoLeak();
- assertTrue(String.format("Leaked slot 0x%08X", slot), slot == -1);
- }
-
- /**
- * Check that IGraphicBufferProducer::queueBuffer does not leak info in error case
- */
- public void test_queueBufferInfoLeak() throws Exception {
- int data = native_test_queueBufferInfoLeak();
- assertTrue(String.format("Leaked buffer data 0x%08X", data), data == 0);
- }
-
- private static native int native_test_attachBufferInfoLeak();
- private static native int native_test_queueBufferInfoLeak();
-}
diff --git a/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java b/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java
deleted file mode 100644
index 900ac7f..0000000
--- a/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2013 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.security.cts;
-
-import junit.framework.TestCase;
-
-public class LoadEffectLibraryTest extends TestCase {
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
- /**
- * Checks that no binder calls to IAudioFlinger manages to load an effect library.
- */
- public void testLoadLibrary() throws Exception {
- assertTrue(doLoadLibraryTest());
- }
-
- private static native boolean doLoadLibraryTest();
-
-}
diff --git a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
deleted file mode 100644
index e34fc05..0000000
--- a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import junit.framework.TestCase;
-
-public class MediaPlayerInfoLeakTest extends TestCase {
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
-
- /**
- * Checks that IMediaPlayer::getCurrentPosition() does not leak info in error case
- */
- public void test_getCurrentPositionLeak() throws Exception {
- int pos = native_test_getCurrentPositionLeak();
- assertTrue(String.format("Leaked pos 0x%08X", pos), pos == 0);
- }
-
- /**
- * Checks that IMediaPlayer::getDuration() does not leak info in error case
- */
- public void test_getDurationLeak() throws Exception {
- int dur = native_test_getDurationLeak();
- assertTrue(String.format("Leaked dur 0x%08X", dur), dur == 0);
- }
-
- private static native int native_test_getCurrentPositionLeak();
- private static native int native_test_getDurationLeak();
-}
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
index a821d97..7a3a81c 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -237,6 +237,7 @@
verifyCallbackTuned();
verifyCommandStartRecording();
verifyCommandStopRecording();
+ verifyCommandSendAppPrivateCommandForRecording();
verifyCallbackRecordingStopped();
verifyCallbackError();
verifyCommandRelease();
@@ -263,7 +264,7 @@
@Override
protected boolean check() {
CountingRecordingSession session = CountingTvInputService.sRecordingSession;
- return session != null && session.mTuneCount > 0;
+ return session != null && session.mTuneWithBundleCount > 0;
}
}.run();
}
@@ -304,6 +305,20 @@
}.run();
}
+ public void verifyCommandSendAppPrivateCommandForRecording() {
+ resetCounts();
+ String action = "android.media.tv.cts.TvInputServiceTest.privateCommand";
+ mTvRecordingClient.sendAppPrivateCommand(action, null);
+ new PollingCheck(TIME_OUT) {
+ @Override
+ protected boolean check() {
+ CountingRecordingSession session = CountingTvInputService.sRecordingSession;
+ return session != null && session.mAppPrivateCommandCount > 0;
+ }
+ }.run();
+ }
+
+
public void verifyCallbackTuned() {
resetCounts();
CountingRecordingSession session = CountingTvInputService.sRecordingSession;
@@ -345,20 +360,6 @@
}.run();
}
- public void verifyCommandSendAppPrivateCommand() {
- resetCounts();
- String action = "android.media.tv.cts.TvInputServiceTest.privateCommand";
- mTvView.sendAppPrivateCommand(action, null);
- mInstrumentation.waitForIdleSync();
- new PollingCheck(TIME_OUT) {
- @Override
- protected boolean check() {
- CountingSession session = CountingTvInputService.sSession;
- return session != null && session.mSendAppPrivateCommand > 0;
- }
- }.run();
- }
-
public void verifyCommandTune() {
resetCounts();
Uri fakeChannelUri = TvContract.buildChannelUri(0);
@@ -382,7 +383,7 @@
@Override
protected boolean check() {
CountingSession session = CountingTvInputService.sSession;
- return session != null && session.mTuneCount > 0;
+ return session != null && session.mTuneWithBundleCount > 0;
}
}.run();
}
@@ -613,6 +614,20 @@
}.run();
}
+ public void verifyCommandSendAppPrivateCommand() {
+ resetCounts();
+ String action = "android.media.tv.cts.TvInputServiceTest.privateCommand";
+ mTvView.sendAppPrivateCommand(action, null);
+ mInstrumentation.waitForIdleSync();
+ new PollingCheck(TIME_OUT) {
+ @Override
+ protected boolean check() {
+ CountingSession session = CountingTvInputService.sSession;
+ return session != null && session.mAppPrivateCommandCount > 0;
+ }
+ }.run();
+ }
+
public void verifyCallbackChannelRetuned() {
resetCounts();
CountingSession session = CountingTvInputService.sSession;
@@ -792,8 +807,8 @@
}
public static class CountingSession extends Session {
- public volatile int mSendAppPrivateCommand;
public volatile int mTuneCount;
+ public volatile int mTuneWithBundleCount;
public volatile int mSetStreamVolumeCount;
public volatile int mSetCaptionEnabledCount;
public volatile int mSelectTrackCount;
@@ -813,14 +828,15 @@
public volatile int mTimeShiftPlayCount;
public volatile long mTimeShiftGetCurrentPositionCount;
public volatile long mTimeShiftGetStartPositionCount;
+ public volatile int mAppPrivateCommandCount;
CountingSession(Context context) {
super(context);
}
public void resetCounts() {
- mSendAppPrivateCommand = 0;
mTuneCount = 0;
+ mTuneWithBundleCount = 0;
mSetStreamVolumeCount = 0;
mSetCaptionEnabledCount = 0;
mSelectTrackCount = 0;
@@ -840,11 +856,7 @@
mTimeShiftPlayCount = 0;
mTimeShiftGetCurrentPositionCount = 0;
mTimeShiftGetStartPositionCount = 0;
- }
-
- @Override
- public void onAppPrivateCommand(String action, Bundle data) {
- mSendAppPrivateCommand++;
+ mAppPrivateCommandCount = 0;
}
@Override
@@ -863,6 +875,15 @@
}
@Override
+ public boolean onTune(Uri channelUri, Bundle data) {
+ mTuneWithBundleCount++;
+ // Also calls {@link #onTune(Uri)} since it will never be called if the
+ // implementation overrides {@link #onTune(Uri, Bundle)}.
+ onTune(channelUri);
+ return false;
+ }
+
+ @Override
public void onSetStreamVolume(float volume) {
mSetStreamVolumeCount++;
}
@@ -965,13 +986,20 @@
public void onOverlayViewSizeChanged(int width, int height) {
mOverlayViewSizeChangedCount++;
}
+
+ @Override
+ public void onAppPrivateCommand(String action, Bundle data) {
+ mAppPrivateCommandCount++;
+ }
}
public static class CountingRecordingSession extends RecordingSession {
public volatile int mTuneCount;
+ public volatile int mTuneWithBundleCount;
public volatile int mReleaseCount;
public volatile int mStartRecordingCount;
public volatile int mStopRecordingCount;
+ public volatile int mAppPrivateCommandCount;
CountingRecordingSession(Context context) {
super(context);
@@ -979,9 +1007,11 @@
public void resetCounts() {
mTuneCount = 0;
+ mTuneWithBundleCount = 0;
mReleaseCount = 0;
mStartRecordingCount = 0;
mStopRecordingCount = 0;
+ mAppPrivateCommandCount = 0;
}
@Override
@@ -990,6 +1020,14 @@
}
@Override
+ public void onTune(Uri channelUri, Bundle data) {
+ mTuneWithBundleCount++;
+ // Also calls {@link #onTune(Uri)} since it will never be called if the
+ // implementation overrides {@link #onTune(Uri, Bundle)}.
+ onTune(channelUri);
+ }
+
+ @Override
public void onRelease() {
mReleaseCount++;
}
@@ -1003,6 +1041,11 @@
public void onStopRecording() {
mStopRecordingCount++;
}
+
+ @Override
+ public void onAppPrivateCommand(String action, Bundle data) {
+ mAppPrivateCommandCount++;
+ }
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
index d0820e2..a2f0305 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -16,7 +16,6 @@
package android.uirendering.cts.testclasses;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
@@ -112,18 +111,15 @@
final Paint paint = new Paint(filterEnum.equals(FilterEnum.ADD_FILTER) ?
0 : Paint.FILTER_BITMAP_FLAG);
- CanvasClient canvasClient = new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.scale(1.0f * width / gridWidth, 1.0f * height / gridWidth);
- if (filterEnum.equals(FilterEnum.ADD_FILTER)) {
- canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
- } else if (filterEnum.equals(FilterEnum.REMOVE_FILTER)) {
- canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
- }
- canvas.drawBitmap(scaleUp ? mSmallGridBitmap : mBigGridBitmap, 0, 0, paint);
- canvas.setDrawFilter(null);
+ CanvasClient canvasClient = (canvas, width, height) -> {
+ canvas.scale(1.0f * width / gridWidth, 1.0f * height / gridWidth);
+ if (filterEnum.equals(FilterEnum.ADD_FILTER)) {
+ canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
+ } else if (filterEnum.equals(FilterEnum.REMOVE_FILTER)) {
+ canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
}
+ canvas.drawBitmap(scaleUp ? mSmallGridBitmap : mBigGridBitmap, 0, 0, paint);
+ canvas.setDrawFilter(null);
};
createTest()
.addCanvasClient(canvasClient)
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
index 38d884d..1e7a832 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -22,7 +22,6 @@
import android.graphics.Region;
import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
@@ -39,17 +38,14 @@
@Test
public void testClipRectReturnValues() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.save();
- boolean isNonEmpty = canvas.clipRect(0, 0, 20, 20);
- assertTrue("clip state should be non empty", isNonEmpty);
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.save();
+ boolean isNonEmpty = canvas.clipRect(0, 0, 20, 20);
+ assertTrue("clip state should be non empty", isNonEmpty);
- isNonEmpty = canvas.clipRect(0, 40, 20, 60);
- assertFalse("clip state should be empty", isNonEmpty);
- canvas.restore();
- }
+ isNonEmpty = canvas.clipRect(0, 40, 20, 60);
+ assertFalse("clip state should be empty", isNonEmpty);
+ canvas.restore();
})
.runWithoutVerification();
}
@@ -57,32 +53,29 @@
@Test
public void testClipRegionReturnValues() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.save();
- RectF clipRectF = new RectF(0, 0, 20, 20);
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.save();
+ RectF clipRectF = new RectF(0, 0, 20, 20);
- assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
- if (!canvas.isHardwareAccelerated()) {
- // SW canvas may not be in View space, so we offset the clipping region
- // so it will operate within the canvas client's window.
- // (Currently, this isn't necessary, since SW layer size == draw area)
- canvas.getMatrix().mapRect(clipRectF);
- }
-
- Region rectRegion = new Region();
- rectRegion.set((int) clipRectF.left, (int) clipRectF.top,
- (int) clipRectF.right, (int) clipRectF.bottom);
-
- boolean isNonEmpty = canvas.clipRegion(rectRegion);
- assertTrue("clip state should be non empty", isNonEmpty);
-
- // Note: we don't test that non-intersecting clip regions empty the clip,
- // For region clipping, the impl is allowed to return true conservatively
- // in many cases.
- canvas.restore();
+ assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
+ if (!canvas.isHardwareAccelerated()) {
+ // SW canvas may not be in View space, so we offset the clipping region
+ // so it will operate within the canvas client's window.
+ // (Currently, this isn't necessary, since SW layer size == draw area)
+ canvas.getMatrix().mapRect(clipRectF);
}
+
+ Region rectRegion = new Region();
+ rectRegion.set((int) clipRectF.left, (int) clipRectF.top,
+ (int) clipRectF.right, (int) clipRectF.bottom);
+
+ boolean isNonEmpty = canvas.clipRegion(rectRegion);
+ assertTrue("clip state should be non empty", isNonEmpty);
+
+ // Note: we don't test that non-intersecting clip regions empty the clip,
+ // For region clipping, the impl is allowed to return true conservatively
+ // in many cases.
+ canvas.restore();
})
.runWithoutVerification();
}
@@ -90,40 +83,34 @@
@Test
public void testClipPathReturnValues() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.save();
- Path rectPath = new Path();
- rectPath.addRect(0, 0, 20, 20, Path.Direction.CW);
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.save();
+ Path rectPath = new Path();
+ rectPath.addRect(0, 0, 20, 20, Path.Direction.CW);
- boolean isNonEmpty = canvas.clipPath(rectPath);
- assertTrue("clip state should be non empty", isNonEmpty);
+ boolean isNonEmpty = canvas.clipPath(rectPath);
+ assertTrue("clip state should be non empty", isNonEmpty);
- rectPath.offset(0, 40);
- isNonEmpty = canvas.clipPath(rectPath);
- assertFalse("clip state should be empty", isNonEmpty);
- canvas.restore();
- }
+ rectPath.offset(0, 40);
+ isNonEmpty = canvas.clipPath(rectPath);
+ assertFalse("clip state should be empty", isNonEmpty);
+ canvas.restore();
})
.runWithoutVerification();
}
@Test
public void testQuickReject() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.save();
- canvas.clipRect(0, 0, 20, 20);
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.save();
+ canvas.clipRect(0, 0, 20, 20);
- // not rejected!
- assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
+ // not rejected!
+ assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
- // rejected!
- assertTrue(canvas.quickReject(0, 40, 20, 60, Canvas.EdgeType.BW));
- canvas.restore();
- }
+ // rejected!
+ assertTrue(canvas.quickReject(0, 40, 20, 60, Canvas.EdgeType.BW));
+ canvas.restore();
})
.runWithoutVerification();
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index bf68f3e..2a2599b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -16,7 +16,6 @@
package android.uirendering.cts.testclasses;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
@@ -28,7 +27,6 @@
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
import android.uirendering.cts.R;
import org.junit.Test;
@@ -40,14 +38,11 @@
public void testBlueRect() {
final Rect rect = new Rect(10, 10, 80, 80);
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint p = new Paint();
- p.setAntiAlias(false);
- p.setColor(Color.BLUE);
- canvas.drawRect(rect, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint p = new Paint();
+ p.setAntiAlias(false);
+ p.setColor(Color.BLUE);
+ canvas.drawRect(rect, p);
})
.runWithVerifier(new RectVerifier(Color.WHITE, Color.BLUE, rect));
}
@@ -55,16 +50,13 @@
@Test
public void testPoints() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint p = new Paint();
- p.setAntiAlias(false);
- p.setStrokeWidth(1f);
- p.setColor(Color.BLACK);
- for (int i = 0; i < 10; i++) {
- canvas.drawPoint(i * 10, i * 10, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint p = new Paint();
+ p.setAntiAlias(false);
+ p.setStrokeWidth(1f);
+ p.setColor(Color.BLACK);
+ for (int i = 0; i < 10; i++) {
+ canvas.drawPoint(i * 10, i * 10, p);
}
})
.runWithComparer(mExactComparer);
@@ -73,17 +65,14 @@
@Test
public void testBlackRectWithStroke() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint p = new Paint();
- p.setColor(Color.RED);
- canvas.drawRect(0, 0, ActivityTestBase.TEST_WIDTH,
- ActivityTestBase.TEST_HEIGHT, p);
- p.setColor(Color.BLACK);
- p.setStrokeWidth(5);
- canvas.drawRect(10, 10, 80, 80, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint p = new Paint();
+ p.setColor(Color.RED);
+ canvas.drawRect(0, 0, ActivityTestBase.TEST_WIDTH,
+ ActivityTestBase.TEST_HEIGHT, p);
+ p.setColor(Color.BLACK);
+ p.setStrokeWidth(5);
+ canvas.drawRect(10, 10, 80, 80, p);
})
.runWithComparer(mExactComparer);
}
@@ -91,15 +80,12 @@
@Test
public void testBlackLineOnGreenBack() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.drawColor(Color.GREEN);
- Paint p = new Paint();
- p.setColor(Color.BLACK);
- p.setStrokeWidth(10);
- canvas.drawLine(0, 0, 50, 0, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.drawColor(Color.GREEN);
+ Paint p = new Paint();
+ p.setColor(Color.BLACK);
+ p.setStrokeWidth(10);
+ canvas.drawLine(0, 0, 50, 0, p);
})
.runWithComparer(mExactComparer);
}
@@ -107,14 +93,11 @@
@Test
public void testDrawRedRectOnBlueBack() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.drawColor(Color.BLUE);
- Paint p = new Paint();
- p.setColor(Color.RED);
- canvas.drawRect(10, 10, 40, 40, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.drawColor(Color.BLUE);
+ Paint p = new Paint();
+ p.setColor(Color.RED);
+ canvas.drawRect(10, 10, 40, 40, p);
})
.runWithComparer(mExactComparer);
}
@@ -122,17 +105,14 @@
@Test
public void testDrawLine() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint p = new Paint();
- canvas.drawColor(Color.WHITE);
- p.setColor(Color.BLACK);
- float[] pts = {
- 0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
- };
- canvas.drawLines(pts, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint p = new Paint();
+ canvas.drawColor(Color.WHITE);
+ p.setColor(Color.BLACK);
+ float[] pts = {
+ 0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
+ };
+ canvas.drawLines(pts, p);
})
.runWithComparer(mExactComparer);
}
@@ -140,12 +120,7 @@
@Test
public void testDrawWhiteScreen() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.drawColor(Color.WHITE);
- }
- })
+ .addCanvasClient((canvas, width, height) -> canvas.drawColor(Color.WHITE))
.runWithComparer(mExactComparer);
}
@@ -153,15 +128,12 @@
public void testBasicText() {
final String testString = "THIS IS A TEST";
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint p = new Paint();
- canvas.drawColor(Color.BLACK);
- p.setColor(Color.WHITE);
- p.setStrokeWidth(5);
- canvas.drawText(testString, 30, 50, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint p = new Paint();
+ canvas.drawColor(Color.BLACK);
+ p.setColor(Color.WHITE);
+ p.setStrokeWidth(5);
+ canvas.drawText(testString, 30, 50, p);
})
.runWithComparer(mExactComparer);
}
@@ -169,12 +141,9 @@
@Test
public void testBasicColorXfermode() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.drawColor(Color.GRAY);
- canvas.drawColor(Color.BLUE, PorterDuff.Mode.MULTIPLY);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.drawColor(Color.GRAY);
+ canvas.drawColor(Color.BLUE, PorterDuff.Mode.MULTIPLY);
})
.runWithComparer(mExactComparer);
}
@@ -189,21 +158,13 @@
new Rect(10, 10, 80, 80));
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.drawColor(Color.WHITE);
- Paint p = new Paint();
- p.setColor(Color.BLUE);
- canvas.drawRect(10, 10, 80, 80, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.drawColor(Color.WHITE);
+ Paint p = new Paint();
+ p.setColor(Color.BLUE);
+ canvas.drawRect(10, 10, 80, 80, p);
})
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- ninePatchDrawable.draw(canvas);
- }
- })
+ .addCanvasClient((canvas, width, height) -> ninePatchDrawable.draw(canvas))
.addLayout(R.layout.blue_padded_square, null)
.runWithVerifier(verifier);
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
index 738dcfb..73779d6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -53,18 +53,15 @@
final Typeface typeface = Typeface.create(family, style);
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(26);
- p.setTypeface(typeface);
- canvas.drawText(sTestString1, 1, 20, p);
- canvas.drawText(sTestString2, 1, 50, p);
- canvas.drawText(sTestString3, 1, 80, p);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setColor(Color.BLACK);
+ p.setTextSize(26);
+ p.setTypeface(typeface);
+ canvas.drawText(sTestString1, 1, 20, p);
+ canvas.drawText(sTestString2, 1, 50, p);
+ canvas.drawText(sTestString3, 1, 80, p);
})
.runWithVerifier(new GoldenImageVerifier(goldenBitmap, comparer));
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index c070b96..212e666 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -19,7 +19,6 @@
import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.R;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
@@ -49,11 +48,8 @@
*/
@Test
public void testRenderSpecIsolation() {
- CanvasClient canvasClient = new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.drawColor(canvas.isHardwareAccelerated() ? Color.BLACK : Color.WHITE);
- }
+ CanvasClient canvasClient = (canvas, width, height) -> {
+ canvas.drawColor(canvas.isHardwareAccelerated() ? Color.BLACK : Color.WHITE);
};
BitmapComparer inverseComparer = new BitmapComparer() {
@Override
@@ -75,12 +71,7 @@
@Test
public void testViewInitializer() {
final Rect clipRect = new Rect(0, 0, 50, 50);
- ViewInitializer viewInitializer = new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- view.setClipBounds(clipRect);
- }
- };
+ ViewInitializer viewInitializer = view -> view.setClipBounds(clipRect);
createTest()
.addLayout(R.layout.simple_red_layout, viewInitializer)
.runWithVerifier(new RectVerifier(Color.WHITE, Color.RED, clipRect));
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index 30dbb03..53112d6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -43,17 +43,14 @@
@ColorInt
final int expectedColor = Color.rgb(255, 191, 191);
createTest()
- .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- // reduce alpha by 50%
- Paint paint = new Paint();
- paint.setAlpha(128);
- view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+ .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+ // reduce alpha by 50%
+ Paint paint = new Paint();
+ paint.setAlpha(128);
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
- // reduce alpha by another 50% (ensuring two alphas combine correctly)
- view.setAlpha(0.5f);
- }
+ // reduce alpha by another 50% (ensuring two alphas combine correctly)
+ view.setAlpha(0.5f);
})
.runWithVerifier(new ColorVerifier(expectedColor));
}
@@ -65,15 +62,12 @@
@ColorInt
final int expectedColor = Color.rgb(54, 54, 54);
createTest()
- .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- Paint paint = new Paint();
- ColorMatrix desatMatrix = new ColorMatrix();
- desatMatrix.setSaturation(0.0f);
- paint.setColorFilter(new ColorMatrixColorFilter(desatMatrix));
- view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
- }
+ .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+ Paint paint = new Paint();
+ ColorMatrix desatMatrix = new ColorMatrix();
+ desatMatrix.setSaturation(0.0f);
+ paint.setColorFilter(new ColorMatrixColorFilter(desatMatrix));
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
})
.runWithVerifier(new ColorVerifier(expectedColor));
}
@@ -85,20 +79,17 @@
@ColorInt
final int expectedColor = Color.WHITE;
createTest()
- .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- Paint paint = new Paint();
- /* Note that when drawing in SW, we're blending within an otherwise empty
- * SW layer, as opposed to in the frame buffer (which has a white
- * background).
- *
- * For this reason we use just use DST, which just throws out the SRC
- * content, regardless of the DST alpha channel.
- */
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
- view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
- }
+ .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+ Paint paint = new Paint();
+ /* Note that when drawing in SW, we're blending within an otherwise empty
+ * SW layer, as opposed to in the frame buffer (which has a white
+ * background).
+ *
+ * For this reason we use just use DST, which just throws out the SRC
+ * content, regardless of the DST alpha channel.
+ */
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
})
.runWithVerifier(new ColorVerifier(expectedColor));
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 03f5e89..7c8a301 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -40,57 +40,41 @@
@MediumTest
public class PathClippingTests extends ActivityTestBase {
// draw circle with hole in it, with stroked circle
- static final CanvasClient sTorusDrawCanvasClient = new CanvasClient() {
- @Override
- public String getDebugString() {
- return "TorusDraw";
- }
-
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint paint = new Paint();
- paint.setAntiAlias(false);
- paint.setColor(Color.BLUE);
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(20);
- canvas.drawCircle(30, 30, 40, paint);
- }
+ static final CanvasClient sTorusDrawCanvasClient = (canvas, width, height) -> {
+ Paint paint = new Paint();
+ paint.setAntiAlias(false);
+ paint.setColor(Color.BLUE);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(20);
+ canvas.drawCircle(30, 30, 40, paint);
};
// draw circle with hole in it, by path operations + path clipping
- static final CanvasClient sTorusClipCanvasClient = new CanvasClient() {
- @Override
- public String getDebugString() {
- return "TorusClipDraw";
- }
+ static final CanvasClient sTorusClipCanvasClient = (canvas, width, height) -> {
+ canvas.save();
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.save();
+ Path path = new Path();
+ path.addCircle(30, 30, 50, Path.Direction.CW);
+ path.addCircle(30, 30, 30, Path.Direction.CCW);
- Path path = new Path();
- path.addCircle(30, 30, 50, Path.Direction.CW);
- path.addCircle(30, 30, 30, Path.Direction.CCW);
+ canvas.clipPath(path);
+ canvas.drawColor(Color.BLUE);
- canvas.clipPath(path);
- canvas.drawColor(Color.BLUE);
-
- canvas.restore();
- }
+ canvas.restore();
};
@Test
public void testCircleWithCircle() {
createTest()
- .addCanvasClient(sTorusDrawCanvasClient, false)
- .addCanvasClient(sTorusClipCanvasClient)
+ .addCanvasClient("TorusDraw", sTorusDrawCanvasClient, false)
+ .addCanvasClient("TorusClip", sTorusClipCanvasClient)
.runWithComparer(new MSSIMComparer(0.90));
}
@Test
public void testCircleWithPoints() {
createTest()
- .addCanvasClient(sTorusClipCanvasClient)
+ .addCanvasClient("TorusClip", sTorusClipCanvasClient)
.runWithVerifier(new SamplePointVerifier(
new Point[] {
// inside of circle
@@ -112,17 +96,13 @@
@Test
public void testViewRotate() {
createTest()
- .addLayout(R.layout.blue_padded_layout, new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- ViewGroup rootView = (ViewGroup) view;
- rootView.setClipChildren(true);
- View childView = rootView.getChildAt(0);
- childView.setPivotX(40);
- childView.setPivotY(40);
- childView.setRotation(45f);
-
- }
+ .addLayout(R.layout.blue_padded_layout, (ViewInitializer) view -> {
+ ViewGroup rootView = (ViewGroup) view;
+ rootView.setClipChildren(true);
+ View childView = rootView.getChildAt(0);
+ childView.setPivotX(40);
+ childView.setPivotY(40);
+ childView.setRotation(45f);
})
.runWithVerifier(new SamplePointVerifier(
new Point[] {
@@ -144,24 +124,21 @@
@Test
public void testTextClip() {
createTest()
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- canvas.save();
+ .addCanvasClient((canvas, width, height) -> {
+ canvas.save();
- Path path = new Path();
- path.addCircle(0, 45, 45, Path.Direction.CW);
- path.addCircle(90, 45, 45, Path.Direction.CW);
- canvas.clipPath(path);
+ Path path = new Path();
+ path.addCircle(0, 45, 45, Path.Direction.CW);
+ path.addCircle(90, 45, 45, Path.Direction.CW);
+ canvas.clipPath(path);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setTextSize(90);
- paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
- canvas.drawText("STRING", 0, 90, paint);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setTextSize(90);
+ paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ canvas.drawText("STRING", 0, 90, paint);
- canvas.restore();
- }
+ canvas.restore();
})
.runWithComparer(new MSSIMComparer(0.90));
}
@@ -173,23 +150,17 @@
}
createTest()
// golden client - draw a simple non-AA circle
- .addCanvasClient(new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint paint = new Paint();
- paint.setAntiAlias(false);
- paint.setColor(Color.BLUE);
- canvas.drawOval(0, 0, width, height, paint);
- }
+ .addCanvasClient((canvas, width, height) -> {
+ Paint paint = new Paint();
+ paint.setAntiAlias(false);
+ paint.setColor(Color.BLUE);
+ canvas.drawOval(0, 0, width, height, paint);
}, false)
// verify against solid color webview, clipped to its parent oval
- .addLayout(R.layout.circle_clipped_webview, new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- WebView webview = (WebView)view.findViewById(R.id.webview);
- assertNotNull(webview);
- webview.loadData("<body style=\"background-color:blue\">", null, null);
- }
+ .addLayout(R.layout.circle_clipped_webview, (ViewInitializer) view -> {
+ WebView webview = (WebView)view.findViewById(R.id.webview);
+ assertNotNull(webview);
+ webview.loadData("<body style=\"background-color:blue\">", null, null);
})
.runWithComparer(new MSSIMComparer(0.95));
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
index 9c8f9ba..a2f3730 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
@@ -25,7 +25,6 @@
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
import org.junit.Test;
@MediumTest
@@ -38,8 +37,8 @@
Paint pt = new Paint();
pt.setColor(Color.GREEN);
Picture pic = new Picture();
- Canvas subcanvas = pic.beginRecording(ActivityTestBase.TEST_WIDTH,
- ActivityTestBase.TEST_HEIGHT);
+ Canvas subcanvas = pic.beginRecording(
+ ActivityTestBase.TEST_WIDTH, ActivityTestBase.TEST_HEIGHT);
subcanvas.drawRect(sRect, pt);
pic.endRecording();
@@ -50,14 +49,11 @@
public void testPictureRespectsClip() throws Exception {
createTest()
.addCanvasClient(
- new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
+ (canvas, width, height) -> {
Picture pic = greenSquare();
canvas.clipRect(sOffsetRect);
pic.draw(canvas); // should be clipped out
}
- }
).runWithVerifier(new ColorVerifier(Color.WHITE));
}
@@ -65,14 +61,11 @@
public void testPictureRespectsTranslate() throws Exception {
createTest()
.addCanvasClient(
- new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
+ (canvas, width, height) -> {
Picture pic = greenSquare();
canvas.translate(40, 0);
pic.draw(canvas); // should be offset
}
- }
).runWithVerifier(
new RectVerifier(Color.WHITE, Color.GREEN, sOffsetRect));
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
index f5f59b3..3f51bbe 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -108,23 +108,21 @@
ResourceModifier.init(getActivity().getResources());
// For each modification combination, we will get the CanvasClient associated with it and
// from there execute a normal canvas test with that.
- CanvasClient canvasClient = new CanvasClient() {
- @Override
- public void draw(Canvas canvas, int width, int height) {
- Paint paint = new Paint();
- modifierAccessor.modifyDrawing(canvas, paint);
- if (drawOp != null) {
- drawOp.modifyDrawing(paint, canvas);
- }
+ CanvasClient canvasClient = (canvas, width, height) -> {
+ Paint paint = new Paint();
+ modifierAccessor.modifyDrawing(canvas, paint);
+ if (drawOp != null) {
+ drawOp.modifyDrawing(paint, canvas);
}
};
int index = 0;
// Create the test cases with each combination
do {
- canvasClient.setDebugString(modifierAccessor.getDebugString());
int arrIndex = Math.min(index, bitmapComparers.length - 1);
- createTest().addCanvasClient(canvasClient).runWithComparer(bitmapComparers[arrIndex]);
+ createTest()
+ .addCanvasClient(modifierAccessor.getDebugString(), canvasClient)
+ .runWithComparer(bitmapComparers[arrIndex]);
index++;
} while (modifierAccessor.step());
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index 3b1df30..c8ca8c3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -2,6 +2,7 @@
import android.graphics.Color;
import android.graphics.Outline;
+import android.graphics.Path;
import android.graphics.Rect;
import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
@@ -15,6 +16,8 @@
import android.uirendering.cts.R;
import org.junit.Test;
+import static org.junit.Assert.assertFalse;
+
/**
* This tests view clipping by modifying properties of blue_padded_layout, and validating
* the resulting rect of content.
@@ -23,46 +26,35 @@
*/
@MediumTest
public class ViewClippingTests extends ActivityTestBase {
- final Rect FULL_RECT = new Rect(0, 0, 90, 90);
- final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
- final Rect PADDED_RECT = new Rect(15, 16, 63, 62);
- final Rect OUTLINE_RECT = new Rect(1, 2, 78, 79);
- final Rect CLIP_BOUNDS_RECT = new Rect(10, 20, 50, 60);
+ static final Rect FULL_RECT = new Rect(0, 0, 90, 90);
+ static final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
+ static final Rect PADDED_RECT = new Rect(15, 16, 63, 62);
+ static final Rect OUTLINE_RECT = new Rect(1, 2, 78, 79);
+ static final Rect CLIP_BOUNDS_RECT = new Rect(10, 20, 50, 60);
- final ViewInitializer BOUNDS_CLIP_INIT = new ViewInitializer() {
- @Override
- public void initializeView(View rootView) {
- ((ViewGroup)rootView).setClipChildren(true);
- }
+ static final ViewInitializer BOUNDS_CLIP_INIT =
+ rootView -> ((ViewGroup)rootView).setClipChildren(true);
+
+ static final ViewInitializer PADDING_CLIP_INIT = rootView -> {
+ ViewGroup child = (ViewGroup) rootView.findViewById(R.id.child);
+ child.setClipToPadding(true);
+ child.setWillNotDraw(true);
+ child.addView(new UnclippedBlueView(rootView.getContext()));
};
- final ViewInitializer PADDING_CLIP_INIT = new ViewInitializer() {
- @Override
- public void initializeView(View rootView) {
- ViewGroup child = (ViewGroup) rootView.findViewById(R.id.child);
- child.setClipToPadding(true);
- child.setWillNotDraw(true);
- child.addView(new UnclippedBlueView(rootView.getContext()));
- }
+
+ static final ViewInitializer OUTLINE_CLIP_INIT = rootView -> {
+ View child = rootView.findViewById(R.id.child);
+ child.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRect(OUTLINE_RECT);
+ }
+ });
+ child.setClipToOutline(true);
};
- final ViewInitializer OUTLINE_CLIP_INIT = new ViewInitializer() {
- @Override
- public void initializeView(View rootView) {
- View child = rootView.findViewById(R.id.child);
- child.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRect(OUTLINE_RECT);
- }
- });
- child.setClipToOutline(true);
- }
- };
- final ViewInitializer CLIP_BOUNDS_CLIP_INIT = new ViewInitializer() {
- @Override
- public void initializeView(View view) {
- view.setClipBounds(CLIP_BOUNDS_RECT);
- }
- };
+
+ static final ViewInitializer CLIP_BOUNDS_CLIP_INIT =
+ view -> view.setClipBounds(CLIP_BOUNDS_RECT);
static BitmapVerifier makeClipVerifier(Rect blueBoundsRect) {
// very high error tolerance, since all these tests care about is clip alignment
@@ -96,6 +88,7 @@
.addLayout(R.layout.blue_padded_layout, PADDING_CLIP_INIT)
.runWithVerifier(makeClipVerifier(PADDED_RECT));
}
+ // TODO: add tests with clip + scroll, and with interesting combinations of the above
@Test
public void testSimpleOutlineClip() {
@@ -110,5 +103,25 @@
.runWithVerifier(makeClipVerifier(FULL_RECT));
}
- // TODO: add tests with clip + scroll, and with interesting combinations of the above
+ @Test
+ public void testOvalOutlineClip() {
+ // In hw this works because clipping to a non-round rect isn't supported, and is no-op'd.
+ // In sw this works because Outline clipping isn't supported.
+ createTest()
+ .addLayout(R.layout.blue_padded_layout, view -> {
+ view.setOutlineProvider(new ViewOutlineProvider() {
+ Path mPath = new Path();
+ @Override
+ public void getOutline(View view, Outline outline) {
+ mPath.reset();
+ mPath.addOval(0, 0, view.getWidth(), view.getHeight(),
+ Path.Direction.CW);
+ outline.setConvexPath(mPath);
+ assertFalse(outline.canClip()); // NOTE: non-round-rect, so can't clip
+ }
+ });
+ view.setClipToOutline(true); // should do nothing, since non-rect clip
+ })
+ .runWithVerifier(makeClipVerifier(FULL_RECT));
+ }
}
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 f82bb40..e634528 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -145,7 +145,7 @@
protected Bitmap captureRenderSpec(TestCase testCase) {
Point testOffset = getActivity().enqueueRenderSpecAndWait(
testCase.layoutID, testCase.canvasClient,
- testCase.webViewUrl, testCase.viewInitializer, testCase.useHardware);
+ null, testCase.viewInitializer, testCase.useHardware);
testCase.wasTestRan = true;
return takeScreenshot(testOffset);
}
@@ -260,36 +260,33 @@
});
}
- public TestCaseBuilder addWebView(String webViewUrl,
- @Nullable ViewInitializer viewInitializer) {
- return addWebView(webViewUrl, viewInitializer, false)
- .addWebView(webViewUrl, viewInitializer, true);
- }
-
public TestCaseBuilder addLayout(int layoutId, @Nullable ViewInitializer viewInitializer) {
return addLayout(layoutId, viewInitializer, false)
.addLayout(layoutId, viewInitializer, true);
}
- public TestCaseBuilder addCanvasClient(CanvasClient canvasClient) {
- return addCanvasClient(canvasClient, false)
- .addCanvasClient(canvasClient, true);
- }
-
- public TestCaseBuilder addWebView(String webViewUrl,
- @Nullable ViewInitializer viewInitializer, boolean useHardware) {
- mTestCases.add(new TestCase(null, 0, webViewUrl, viewInitializer, useHardware));
- return this;
- }
-
public TestCaseBuilder addLayout(int layoutId, @Nullable ViewInitializer viewInitializer,
- boolean useHardware) {
- mTestCases.add(new TestCase(null, layoutId, null, viewInitializer, useHardware));
+ boolean useHardware) {
+ mTestCases.add(new TestCase(layoutId, viewInitializer, useHardware));
return this;
}
+ public TestCaseBuilder addCanvasClient(CanvasClient canvasClient) {
+ return addCanvasClient(null, canvasClient);
+ }
+
public TestCaseBuilder addCanvasClient(CanvasClient canvasClient, boolean useHardware) {
- mTestCases.add(new TestCase(canvasClient, 0, null, null, useHardware));
+ return addCanvasClient(null, canvasClient, useHardware);
+ }
+
+ public TestCaseBuilder addCanvasClient(String debugString, CanvasClient canvasClient) {
+ return addCanvasClient(debugString, canvasClient, false)
+ .addCanvasClient(debugString, canvasClient, true);
+ }
+
+ public TestCaseBuilder addCanvasClient(String debugString,
+ CanvasClient canvasClient, boolean useHardware) {
+ mTestCases.add(new TestCase(canvasClient, debugString, useHardware));
return this;
}
@@ -300,39 +297,35 @@
private class TestCase {
public int layoutID;
- public CanvasClient canvasClient;
- public String webViewUrl;
public ViewInitializer viewInitializer;
- public boolean useHardware;
- public boolean wasTestRan;
- public TestCase(CanvasClient client, int id, String viewUrl,
- ViewInitializer viewInitializer, boolean useHardware) {
- int count = 0;
- count += (client == null ? 0 : 1);
- count += (viewUrl == null ? 0 : 1);
- count += (id == 0 ? 0 : 1);
- assert(count == 1);
- assert(client == null || viewInitializer == null);
- this.layoutID = id;
- this.canvasClient = client;
- this.webViewUrl = viewUrl;
+ public CanvasClient canvasClient;
+ public String canvasClientDebugString;
+
+ public boolean useHardware;
+ public boolean wasTestRan = false;
+
+ public TestCase(int layoutId, ViewInitializer viewInitializer, boolean useHardware) {
+ this.layoutID = layoutId;
this.viewInitializer = viewInitializer;
this.useHardware = useHardware;
- this.wasTestRan = false;
+ }
+
+ public TestCase(CanvasClient client, String debugString, boolean useHardware) {
+ this.canvasClient = client;
+ this.canvasClientDebugString = debugString;
+ this.useHardware = useHardware;
}
public String getDebugString() {
String debug = "";
if (canvasClient != null) {
debug += "CanvasClient : ";
- if (canvasClient.getDebugString() != null) {
- debug += canvasClient.getDebugString();
+ if (canvasClientDebugString != null) {
+ debug += canvasClientDebugString;
} else {
debug += "no debug string given";
}
- } else if (webViewUrl != null) {
- debug += "WebView URL : " + webViewUrl;
} else {
debug += "Layout resource : " +
getActivity().getResources().getResourceName(layoutID);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java
index a99c576..99f6cc7 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java
@@ -20,16 +20,6 @@
/**
* A class that the tester will implement and create a set of drawing calls the tests would use
*/
-public abstract class CanvasClient {
- private String mDebugString;
-
- public abstract void draw(Canvas canvas, int width, int height);
-
- public String getDebugString() {
- return mDebugString;
- }
-
- public void setDebugString(String debugString) {
- mDebugString = debugString;
- }
+public interface CanvasClient {
+ void draw(Canvas canvas, int width, int height);
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
index 9a3cbb1..43e1fa6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
@@ -20,6 +20,6 @@
/**
* Called after a view is created to set various properties on the view
*/
-public abstract class ViewInitializer {
- public abstract void initializeView(View view);
+public interface ViewInitializer {
+ void initializeView(View view);
}
diff --git a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
index b25f733..ccf37949 100644
--- a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
+++ b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
@@ -17,6 +17,7 @@
package android.view.cts;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
@@ -25,7 +26,6 @@
import android.view.cts.R;
-
public class ContextThemeWrapperTest extends AndroidTestCase {
private static final int SYSTEM_DEFAULT_THEME = 0;
@@ -103,6 +103,22 @@
}).test());
}
+ public void testApplyOverrideConfiguration() {
+ Context context = getContext();
+ final int realDensity = context.getResources().getConfiguration().densityDpi;
+ final int expectedDensity = realDensity + 1;
+
+ ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(
+ context, SYSTEM_DEFAULT_THEME);
+
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.densityDpi = expectedDensity;
+ contextThemeWrapper.applyOverrideConfiguration(overrideConfig);
+
+ Configuration actualConfiguration = contextThemeWrapper.getResources().getConfiguration();
+ assertEquals(expectedDensity, actualConfiguration.densityDpi);
+ }
+
private void assertEqualsTextAppearanceStyle(TypedArray ta) {
final int defValue = -1;
// get Theme and assert
diff --git a/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java b/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
new file mode 100644
index 0000000..067f0bb
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
@@ -0,0 +1,97 @@
+package android.view.cts;
+
+import android.os.Parcel;
+import android.test.InstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link android.view.KeyboardShortcutGroup}.
+ */
+public class KeyboardShortcutGroupTest extends InstrumentationTestCase {
+ private static final CharSequence TEST_LABEL = "Test Group Label";
+ private final List<KeyboardShortcutInfo> TEST_ITEMS = Lists.newArrayList(
+ new KeyboardShortcutInfo("Item 1", KeyEvent.KEYCODE_U, KeyEvent.META_CTRL_ON),
+ new KeyboardShortcutInfo("Item 2", KeyEvent.KEYCODE_F, KeyEvent.META_CTRL_ON));
+
+ public void testConstructor() {
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS);
+
+ assertEquals(TEST_LABEL, group.getLabel());
+ assertEquals(TEST_ITEMS, group.getItems());
+ assertFalse(group.isSystemGroup());
+ assertEquals(0, group.describeContents());
+ }
+
+ public void testShortConstructor() {
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL);
+
+ assertEquals(TEST_LABEL, group.getLabel());
+ assertNotNull(group.getItems());
+ assertFalse(group.isSystemGroup());
+ assertEquals(0, group.describeContents());
+ }
+
+ public void testSystemConstructor() {
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS, true);
+
+ assertEquals(TEST_LABEL, group.getLabel());
+ assertEquals(TEST_ITEMS, group.getItems());
+ assertTrue(group.isSystemGroup());
+ assertEquals(0, group.describeContents());
+ }
+
+ public void testSystemShortConstructor() {
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, true);
+
+ assertEquals(TEST_LABEL, group.getLabel());
+ assertNotNull(group.getItems());
+ assertTrue(group.isSystemGroup());
+ assertEquals(0, group.describeContents());
+ }
+
+ public void testConstructorChecksList() {
+ try {
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, null);
+ } catch (NullPointerException expected) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAddItem() {
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS);
+
+ group.addItem(new KeyboardShortcutInfo(
+ "Additional item", KeyEvent.KEYCODE_P, KeyEvent.META_CTRL_ON));
+
+ final int newSize = group.getItems().size();
+ assertEquals(TEST_ITEMS.size() + 1, newSize);
+ assertEquals("Additional item", group.getItems().get(newSize - 1).getLabel());
+ }
+
+ public void testWriteToParcelAndRead() {
+ Parcel dest = Parcel.obtain();
+ KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS, true);
+ group.writeToParcel(dest, 0);
+
+ dest.setDataPosition(0);
+ KeyboardShortcutGroup result = KeyboardShortcutGroup.CREATOR.createFromParcel(dest);
+
+ assertEquals(TEST_LABEL, result.getLabel());
+ assertEquals(TEST_ITEMS.size(), result.getItems().size());
+ assertEquals(TEST_ITEMS.get(0).getLabel(), result.getItems().get(0).getLabel());
+ assertEquals(TEST_ITEMS.get(1).getLabel(), result.getItems().get(1).getLabel());
+ assertEquals(TEST_ITEMS.get(0).getKeycode(), result.getItems().get(0).getKeycode());
+ assertEquals(TEST_ITEMS.get(1).getKeycode(), result.getItems().get(1).getKeycode());
+ assertEquals(TEST_ITEMS.get(0).getModifiers(), result.getItems().get(0).getModifiers());
+ assertEquals(TEST_ITEMS.get(1).getModifiers(), result.getItems().get(1).getModifiers());
+ assertTrue(result.isSystemGroup());
+ }
+}
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 5acfc18..11057a5 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -77,7 +77,15 @@
</activity>
<activity android:name="android.widget.cts.ImageViewCtsActivity"
- android:label="ImageViewCtsActivity">
+ android:label="ImageViewCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.SwitchCtsActivity"
+ android:label="SwitchCtsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
diff --git a/tests/tests/widget/res/layout/popupwindow.xml b/tests/tests/widget/res/layout/popupwindow.xml
index d84770d..cf69831 100644
--- a/tests/tests/widget/res/layout/popupwindow.xml
+++ b/tests/tests/widget/res/layout/popupwindow.xml
@@ -20,40 +20,76 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.widget.cts.MockViewForListPopupWindow
+ <View
android:id="@+id/anchor_upper_left"
android:layout_width="10dp"
android:layout_height="10dp"
- android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
- android:background="#f0f" />
-
- <View android:id="@+id/anchor_upper"
- android:layout_width="10dp"
- android:layout_height="30dp"
android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
android:background="#f00" />
- <View android:id="@+id/anchor_lower"
+ <View
+ android:id="@+id/anchor_upper"
android:layout_width="10dp"
- android:layout_height="30dp"
- android:layout_alignParentBottom="true"
+ android:layout_height="10dp"
android:layout_centerHorizontal="true"
- android:background="#0f0" />
+ android:layout_alignParentTop="true"
+ android:background="#f00" />
- <View android:id="@+id/anchor_middle_left"
- android:layout_width="30dp"
+ <View
+ android:id="@+id/anchor_upper_right"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:background="#f00" />
+
+ <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" />
+ android:background="#0f0" />
- <View android:id="@+id/anchor_middle_right"
- android:layout_width="30dp"
+ <View
+ android:id="@+id/anchor_middle"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:background="#0f0" />
+
+ <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" />
+ android:background="#0f0" />
+
+ <View
+ android:id="@+id/anchor_lower_left"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:background="#00f" />
+
+ <View
+ android:id="@+id/anchor_lower"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:background="#00f" />
+
+ <View
+ android:id="@+id/anchor_lower_right"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentBottom="true"
+ android:background="#00f" />
</RelativeLayout>
diff --git a/tests/tests/widget/res/layout/switch_layout.xml b/tests/tests/widget/res/layout/switch_layout.xml
index a34845b..12e10d2 100644
--- a/tests/tests/widget/res/layout/switch_layout.xml
+++ b/tests/tests/widget/res/layout/switch_layout.xml
@@ -16,6 +16,7 @@
-->
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/switch_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:thumbTint="@android:color/white"
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index da22652..478dd854 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -188,4 +188,6 @@
<item name="android:tabStripLeft">@drawable/icon_green</item>
<item name="android:tabStripRight">@drawable/icon_red</item>
</style>
+
+ <style name="ToolbarPopupTheme_Test" parent="@android:style/ThemeOverlay.Material.Light" />
</resources>
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 3054bab..cb7f2d6 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.Gravity;
@@ -29,6 +28,7 @@
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
+import android.widget.EditText;
import android.widget.PopupMenu;
import static org.mockito.Mockito.*;
@@ -51,6 +51,19 @@
super.setUp();
mInstrumentation = getInstrumentation();
mActivity = getActivity();
+
+ try {
+ runTestOnUiThread(() -> {
+ // Disable and remove focusability on the first child of our activity so that
+ // it doesn't bring in the soft keyboard that can mess up with some of the tests
+ // (such as menu dismissal when we emulate a tap outside the menu bounds).
+ final EditText editText = (EditText) mActivity.findViewById(R.id.anchor_upper_left);
+ editText.setEnabled(false);
+ editText.setFocusable(false);
+ });
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
}
@Override
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 658307a..15a79bf 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,12 +16,16 @@
package android.widget.cts;
+import junit.framework.AssertionFailedError;
+
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.Rect;
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;
@@ -296,33 +300,281 @@
assertEquals(width, mPopupWindow.getWidth());
}
+ private static final int TOP = 0x00;
+ private static final int BOTTOM = 0x01;
+
+ private static final int LEFT = 0x00;
+ private static final int RIGHT = 0x01;
+
+ private static final int GREATER_THAN = 1;
+ private static final int LESS_THAN = -1;
+ private static final int EQUAL_TO = 0;
+
public void testShowAsDropDown() {
- int[] anchorXY = new int[2];
- int[] viewOnScreenXY = new int[2];
- int[] viewInWindowXY = new int[2];
+ final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+ popup.setClipToScreenEnabled(false);
+ popup.setOverlapAnchor(false);
+ popup.setAnimationStyle(0);
+ popup.setExitTransition(null);
+ popup.setEnterTransition(null);
- mPopupWindow = createPopupWindow(createPopupContent());
- final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
+ assertPosition(popup, R.id.anchor_upper_left,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_upper,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_upper_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
- mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(upperAnchor));
- mInstrumentation.waitForIdleSync();
+ assertPosition(popup, R.id.anchor_middle_left,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_middle,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_middle_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
- assertTrue(mPopupWindow.isShowing());
+ assertPosition(popup, R.id.anchor_lower_left,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_lower,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_lower_right,
+ RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
+ }
- mPopupWindow.getContentView().getLocationOnScreen(viewOnScreenXY);
- upperAnchor.getLocationOnScreen(anchorXY);
- mPopupWindow.getContentView().getLocationInWindow(viewInWindowXY);
- assertEquals(anchorXY[0] + viewInWindowXY[0], viewOnScreenXY[0]);
- assertEquals(anchorXY[1] + viewInWindowXY[1] + upperAnchor.getHeight(), viewOnScreenXY[1]);
+ public void testShowAsDropDown_ClipToScreen() {
+ final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+ popup.setClipToScreenEnabled(true);
+ popup.setOverlapAnchor(false);
+ popup.setAnimationStyle(0);
+ popup.setExitTransition(null);
+ popup.setEnterTransition(null);
- dismissPopup();
+ assertPosition(popup, R.id.anchor_upper_left,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_upper,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_upper_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
+
+ assertPosition(popup, R.id.anchor_middle_left,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_middle,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_middle_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
+
+ assertPosition(popup, R.id.anchor_lower_left,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_lower,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_lower_right,
+ RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
+ }
+
+ public void testShowAsDropDown_ClipToScreen_Overlap() {
+ final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+ popup.setClipToScreenEnabled(true);
+ popup.setOverlapAnchor(true);
+ popup.setAnimationStyle(0);
+ popup.setExitTransition(null);
+ popup.setEnterTransition(null);
+
+ assertPosition(popup, R.id.anchor_upper_left,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_upper,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_upper_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, TOP);
+
+ assertPosition(popup, R.id.anchor_middle_left,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_middle,
+ LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_middle_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, TOP);
+
+ assertPosition(popup, R.id.anchor_lower_left,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_lower,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+ assertPosition(popup, R.id.anchor_lower_right,
+ RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
+ }
+
+ public void testShowAsDropDown_ClipToScreen_Overlap_Offset() {
+ final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+ popup.setClipToScreenEnabled(true);
+ popup.setOverlapAnchor(true);
+ popup.setAnimationStyle(0);
+ popup.setExitTransition(null);
+ popup.setEnterTransition(null);
+
+ final int offsetX = mActivity.findViewById(R.id.anchor_upper).getWidth() / 2;
+ final int offsetY = mActivity.findViewById(R.id.anchor_upper).getHeight() / 2;
+ final int gravity = Gravity.TOP | Gravity.START;
+
+ assertPosition(popup, R.id.anchor_upper_left,
+ LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+ offsetX, offsetY, gravity);
+ assertPosition(popup, R.id.anchor_upper,
+ LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+ offsetX, offsetY, gravity);
+ assertPosition(popup, R.id.anchor_upper_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, GREATER_THAN, TOP,
+ offsetX, offsetY, gravity);
+
+ assertPosition(popup, R.id.anchor_middle_left,
+ LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+ offsetX, offsetY, gravity);
+ assertPosition(popup, R.id.anchor_middle,
+ LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+ offsetX, offsetY, gravity);
+ assertPosition(popup, R.id.anchor_middle_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, GREATER_THAN, TOP,
+ offsetX, offsetY, gravity);
+
+ assertPosition(popup, R.id.anchor_lower_left,
+ LEFT, GREATER_THAN, LEFT, BOTTOM, LESS_THAN, BOTTOM,
+ offsetX, offsetY, gravity);
+ assertPosition(popup, R.id.anchor_lower,
+ LEFT, GREATER_THAN, LEFT, BOTTOM, LESS_THAN, BOTTOM,
+ offsetX, offsetY, gravity);
+ assertPosition(popup, R.id.anchor_lower_right,
+ RIGHT, EQUAL_TO, RIGHT, BOTTOM, LESS_THAN, BOTTOM,
+ offsetX, offsetY, gravity);
+ }
+
+ public void testShowAsDropDown_ClipToScreen_TooBig() {
+ final View rootView = mActivity.findViewById(R.id.anchor_upper_left).getRootView();
+ final int width = rootView.getWidth() * 2;
+ final int height = rootView.getHeight() * 2;
+
+ final PopupWindow popup = createPopupWindow(createPopupContent(width, height));
+ popup.setWidth(width);
+ popup.setHeight(height);
+
+ popup.setClipToScreenEnabled(true);
+ popup.setOverlapAnchor(false);
+ popup.setAnimationStyle(0);
+ popup.setExitTransition(null);
+ popup.setEnterTransition(null);
+
+ assertPosition(popup, R.id.anchor_upper_left,
+ LEFT, EQUAL_TO, LEFT, TOP, LESS_THAN, TOP);
+ assertPosition(popup, R.id.anchor_upper,
+ LEFT, LESS_THAN, LEFT, TOP, LESS_THAN, TOP);
+ assertPosition(popup, R.id.anchor_upper_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, LESS_THAN, TOP);
+
+ assertPosition(popup, R.id.anchor_middle_left,
+ LEFT, EQUAL_TO, LEFT, TOP, LESS_THAN, TOP);
+ assertPosition(popup, R.id.anchor_middle,
+ LEFT, LESS_THAN, LEFT, TOP, LESS_THAN, TOP);
+ assertPosition(popup, R.id.anchor_middle_right,
+ RIGHT, EQUAL_TO, RIGHT, TOP, LESS_THAN, TOP);
+
+ assertPosition(popup, R.id.anchor_lower_left,
+ LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_lower,
+ LEFT, LESS_THAN, LEFT, BOTTOM, EQUAL_TO, BOTTOM);
+ assertPosition(popup, R.id.anchor_lower_right,
+ RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, BOTTOM);
+ }
+
+ private void assertPosition(PopupWindow popup, int anchorId,
+ int contentEdgeX, int operatorX, int anchorEdgeX,
+ int contentEdgeY, int operatorY, int anchorEdgeY) {
+ assertPosition(popup, anchorId,
+ contentEdgeX, operatorX, anchorEdgeX,
+ contentEdgeY, operatorY, anchorEdgeY,
+ 0, 0, Gravity.TOP | Gravity.START);
+ }
+
+ private void assertPosition(PopupWindow popup, int anchorId,
+ int contentEdgeX, int operatorX, int anchorEdgeX,
+ int contentEdgeY, int operatorY, int anchorEdgeY,
+ int offsetX, int offsetY, int gravity) {
+ final View content = popup.getContentView();
+ final View anchor = mActivity.findViewById(anchorId);
+
+ getInstrumentation().runOnMainSync(() -> popup.showAsDropDown(
+ anchor, offsetX, offsetY, gravity));
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue(popup.isShowing());
+ assertPositionX(content, contentEdgeX, operatorX, anchor, anchorEdgeX);
+ assertPositionY(content, contentEdgeY, operatorY, anchor, anchorEdgeY);
+
+ // Make sure it fits in the display frame.
+ final Rect displayFrame = new Rect();
+ anchor.getWindowVisibleDisplayFrame(displayFrame);
+ final Rect contentFrame = new Rect();
+ content.getBoundsOnScreen(contentFrame);
+ assertTrue("Content (" + contentFrame + ") extends outside display (" + displayFrame + ")",
+ displayFrame.contains(contentFrame));
+
+ getInstrumentation().runOnMainSync(() -> popup.dismiss());
+ getInstrumentation().waitForIdleSync();
+
+ assertFalse(popup.isShowing());
+ }
+
+ public static void assertPositionY(View content, int contentEdge, int flags,
+ View anchor, int anchorEdge) {
+ final int[] anchorOnScreenXY = new int[2];
+ anchor.getLocationOnScreen(anchorOnScreenXY);
+ int anchorY = anchorOnScreenXY[1];
+ if ((anchorEdge & BOTTOM) == BOTTOM) {
+ anchorY += anchor.getHeight();
+ }
+
+ final int[] contentOnScreenXY = new int[2];
+ content.getLocationOnScreen(contentOnScreenXY);
+ int contentY = contentOnScreenXY[1];
+ if ((contentEdge & BOTTOM) == BOTTOM) {
+ contentY += content.getHeight();
+ }
+
+ assertComparison(contentY, flags, anchorY);
+ }
+
+ private static void assertPositionX(View content, int contentEdge, int flags,
+ View anchor, int anchorEdge) {
+ final int[] anchorOnScreenXY = new int[2];
+ anchor.getLocationOnScreen(anchorOnScreenXY);
+ int anchorX = anchorOnScreenXY[0];
+ if ((anchorEdge & RIGHT) == RIGHT) {
+ anchorX += anchor.getWidth();
+ }
+
+ final int[] contentOnScreenXY = new int[2];
+ content.getLocationOnScreen(contentOnScreenXY);
+ int contentX = contentOnScreenXY[0];
+ if ((contentEdge & RIGHT) == RIGHT) {
+ contentX += content.getWidth();
+ }
+
+ assertComparison(contentX, flags, anchorX);
+ }
+
+ private static void assertComparison(int left, int operator, int right) {
+ switch (operator) {
+ case GREATER_THAN:
+ assertTrue(left + " <= " + right, left > right);
+ break;
+ case LESS_THAN:
+ assertTrue(left + " >= " + right, left < right);
+ break;
+ case EQUAL_TO:
+ assertTrue(left + " != " + right, left == right);
+ break;
+ }
}
public void testShowAtLocation() {
int[] popupContentViewInWindowXY = new int[2];
int[] popupContentViewOnScreenXY = new int[2];
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
// Do not attach within the decor; we will be measuring location
// with regard to screen coordinates.
mPopupWindow.setAttachedInDecor(false);
@@ -355,7 +607,7 @@
int[] viewOnScreenXY = new int[2];
int[] viewInWindowXY = new int[2];
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
upperAnchor.getLocationOnScreen(anchorXY);
int height = upperAnchor.getHeight();
@@ -379,7 +631,7 @@
int[] viewOnScreenXY = new int[2];
int[] viewInWindowXY = new int[2];
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
upperAnchor.getLocationOnScreen(anchorXY);
@@ -397,7 +649,7 @@
}
public void testAccessWindowLayoutType() {
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
mPopupWindow.getWindowLayoutType());
mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
@@ -406,7 +658,7 @@
}
public void testGetMaxAvailableHeight() {
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
View anchorView = mActivity.findViewById(R.id.anchor_upper);
int avaliable = getDisplay().getHeight() - anchorView.getHeight();
@@ -447,7 +699,7 @@
@UiThreadTest
public void testDismiss() {
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
assertFalse(mPopupWindow.isShowing());
View anchorView = mActivity.findViewById(R.id.anchor_upper);
mPopupWindow.showAsDropDown(anchorView);
@@ -480,7 +732,7 @@
}
public void testUpdate() {
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
mPopupWindow.setBackgroundDrawable(null);
showPopup();
@@ -529,7 +781,7 @@
OnDismissListener dismissListener = mock(OnDismissListener.class);
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
mPopupWindow.setEnterTransition(enterTransition);
mPopupWindow.setExitTransition(exitTransition);
mPopupWindow.setOnDismissListener(dismissListener);
@@ -557,7 +809,7 @@
int[] viewInWindowXY = new int[2];
mInstrumentation.runOnMainSync(() -> {
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
// Do not attach within the decor; we will be measuring location
// with regard to screen coordinates.
mPopupWindow.setAttachedInDecor(false);
@@ -601,7 +853,7 @@
public void testUpdateDimensionAndAlignAnchorView() {
mInstrumentation.runOnMainSync(
- () -> mPopupWindow = createPopupWindow(createPopupContent()));
+ () -> mPopupWindow = createPopupWindow(createPopupContent(50, 50)));
mInstrumentation.waitForIdleSync();
final View anchorView = mActivity.findViewById(R.id.anchor_upper);
@@ -636,7 +888,7 @@
int[] viewInWindowOff = new int[2];
int[] viewXY = new int[2];
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
final View anchorView = mActivity.findViewById(R.id.anchor_upper);
// Do not update if it is not shown
assertFalse(mPopupWindow.isShowing());
@@ -737,7 +989,8 @@
}
public void testIsAboveAnchor() {
- mInstrumentation.runOnMainSync(() -> mPopupWindow = createPopupWindow(createPopupContent()));
+ mInstrumentation.runOnMainSync(() -> mPopupWindow = createPopupWindow(createPopupContent(50,
+ 50)));
mInstrumentation.waitForIdleSync();
final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
@@ -746,7 +999,7 @@
assertFalse(mPopupWindow.isAboveAnchor());
dismissPopup();
- mPopupWindow = createPopupWindow(createPopupContent());
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
final View lowerAnchor = mActivity.findViewById(R.id.anchor_lower);
mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(lowerAnchor, 0, 0));
@@ -819,9 +1072,9 @@
public void captureEndValues(TransitionValues transitionValues) {}
}
- private View createPopupContent() {
- View popupView = new View(mActivity);
- popupView.setLayoutParams(new ViewGroup.LayoutParams(50, 50));
+ private View createPopupContent(int width, int height) {
+ final View popupView = new View(mActivity);
+ popupView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
popupView.setBackgroundColor(Color.MAGENTA);
return popupView;
@@ -831,6 +1084,7 @@
PopupWindow window = new PopupWindow(mActivity);
window.setWidth(100);
window.setHeight(100);
+ window.setBackgroundDrawable(new ColorDrawable(Color.YELLOW));
return window;
}
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SwitchCtsActivity.java
new file mode 100644
index 0000000..7be5831
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SwitchCtsActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Switch;
+import android.widget.cts.R;
+
+/**
+ * A minimal application for {@link Switch} test.
+ */
+public class SwitchCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.switch_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchTest.java b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
index e1124f3..216b17b 100644
--- a/tests/tests/widget/src/android/widget/cts/SwitchTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
@@ -16,65 +16,71 @@
package android.widget.cts;
-import android.widget.cts.R;
-
-import android.content.Context;
+import android.app.Activity;
import android.content.res.ColorStateList;
-import android.content.res.XmlResourceParser;
-import android.cts.util.WidgetTestUtils;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
-import android.test.AndroidTestCase;
-import android.util.Xml;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.widget.Switch;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import org.xmlpull.v1.XmlPullParserException;
/**
* Test {@link Switch}.
*/
-public class SwitchTest extends AndroidTestCase {
- public void testConstructor() throws XmlPullParserException, IOException {
- new Switch(mContext);
+@SmallTest
+public class SwitchTest extends ActivityInstrumentationTestCase<SwitchCtsActivity> {
+ private Activity mActivity;
+ private Switch mSwitch;
- XmlResourceParser parser = mContext.getResources().getLayout(R.layout.switch_layout);
- WidgetTestUtils.beginDocument(parser, "Switch");
-
- new Switch(mContext, parser);
-
- new Switch(mContext, parser, 0);
-
- new Switch(mContext, parser, 0, 0);
+ public SwitchTest() {
+ super("android.widget.cts", SwitchCtsActivity.class);
}
- public void testAccessThumbTint() throws XmlPullParserException, IOException {
- XmlResourceParser parser = mContext.getResources().getLayout(R.layout.switch_layout);
- WidgetTestUtils.beginDocument(parser, "Switch");
- Switch aSwitch = new Switch(mContext, parser);
- assertEquals(Color.WHITE, aSwitch.getThumbTintList().getDefaultColor());
- assertEquals(Mode.SRC_OVER, aSwitch.getThumbTintMode());
-
- ColorStateList colors = ColorStateList.valueOf(Color.RED);
- aSwitch.setThumbTintList(colors);
- aSwitch.setThumbTintMode(Mode.XOR);
-
- assertSame(colors, aSwitch.getThumbTintList());
- assertEquals(Mode.XOR, aSwitch.getThumbTintMode());
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mSwitch = (Switch) mActivity.findViewById(R.id.switch_view);
}
- public void testAccessTrackTint() throws XmlPullParserException, IOException {
- XmlResourceParser parser = mContext.getResources().getLayout(R.layout.switch_layout);
- WidgetTestUtils.beginDocument(parser, "Switch");
- Switch aSwitch = new Switch(mContext, parser);
- assertEquals(Color.BLACK, aSwitch.getTrackTintList().getDefaultColor());
- assertEquals(Mode.SRC_ATOP, aSwitch.getTrackTintMode());
+ @UiThreadTest
+ public void testConstructor() {
+ new Switch(mActivity);
+
+ new Switch(mActivity, null);
+
+ new Switch(mActivity, null, android.R.attr.switchStyle);
+
+ new Switch(mActivity, null, 0, android.R.style.Widget_Material_Light_CompoundButton_Switch);
+ }
+
+ @UiThreadTest
+ public void testAccessThumbTint() {
+ assertEquals(Color.WHITE, mSwitch.getThumbTintList().getDefaultColor());
+ assertEquals(Mode.SRC_OVER, mSwitch.getThumbTintMode());
ColorStateList colors = ColorStateList.valueOf(Color.RED);
- aSwitch.setTrackTintList(colors);
- aSwitch.setTrackTintMode(Mode.XOR);
+ mSwitch.setThumbTintList(colors);
+ mSwitch.setThumbTintMode(Mode.XOR);
- assertSame(colors, aSwitch.getTrackTintList());
- assertEquals(Mode.XOR, aSwitch.getTrackTintMode());
+ assertSame(colors, mSwitch.getThumbTintList());
+ assertEquals(Mode.XOR, mSwitch.getThumbTintMode());
+ }
+
+ @UiThreadTest
+ public void testAccessTrackTint() {
+ assertEquals(Color.BLACK, mSwitch.getTrackTintList().getDefaultColor());
+ assertEquals(Mode.SRC_ATOP, mSwitch.getTrackTintMode());
+
+ ColorStateList colors = ColorStateList.valueOf(Color.RED);
+ mSwitch.setTrackTintList(colors);
+ mSwitch.setTrackTintMode(Mode.XOR);
+
+ assertSame(colors, mSwitch.getTrackTintList());
+ assertEquals(Mode.XOR, mSwitch.getTrackTintMode());
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
index 0fd98c0..7f9690c 100644
--- a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
@@ -17,6 +17,9 @@
package android.widget.cts;
import android.app.Instrumentation;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
@@ -24,6 +27,7 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.widget.ListPopupWindow;
import android.widget.Toolbar;
import android.widget.cts.util.TestUtils;
import android.widget.cts.util.ViewTestUtils;
@@ -46,6 +50,16 @@
mMainToolbar = mActivity.getMainToolbar();
}
+ public void testConstructor() {
+ new Toolbar(mActivity);
+
+ new Toolbar(mActivity, null);
+
+ new Toolbar(mActivity, null, android.R.attr.toolbarStyle);
+
+ new Toolbar(mActivity, null, 0, android.R.style.Widget_Material_Toolbar);
+ }
+
public void testTitleAndSubtitleContent() {
// Note that this method is *not* annotated to run on the UI thread, and every
// call to setTitle / setSubtitle is wrapped to wait until the next draw pass
@@ -72,6 +86,30 @@
assertEquals("New subtitle", mMainToolbar.getSubtitle());
}
+ public void testTitleAndSubtitleAppearance() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ () -> mMainToolbar.setTitle(R.string.toolbar_title));
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ () -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
+
+ // Since there are no APIs to get reference to the underlying implementation of
+ // title and subtitle, here we are testing that calling the relevant APIs doesn't crash
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ () -> mMainToolbar.setTitleTextColor(Color.RED));
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ () -> mMainToolbar.setSubtitleTextColor(Color.BLUE));
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ () -> mMainToolbar.setTitleTextAppearance(
+ mActivity, R.style.TextAppearance_NotColors));
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ () -> mMainToolbar.setSubtitleTextAppearance(
+ mActivity, R.style.TextAppearance_WithColor));
+ }
+
@UiThreadTest
public void testGetTitleMargins() {
assertEquals(5, mMainToolbar.getTitleMarginStart());
@@ -326,4 +364,22 @@
assertEquals(40, mMainToolbar.getContentInsetRight());
assertEquals(20, mMainToolbar.getContentInsetEnd());
}
+
+ @UiThreadTest
+ public void testPopupTheme() {
+ mMainToolbar.setPopupTheme(R.style.ToolbarPopupTheme_Test);
+ assertEquals(R.style.ToolbarPopupTheme_Test, mMainToolbar.getPopupTheme());
+ }
+
+ public void testNavigationOnClickListener() {
+ View.OnClickListener mockListener = mock(View.OnClickListener.class);
+ mMainToolbar.setNavigationOnClickListener(mockListener);
+
+ verify(mockListener, never()).onClick(any(View.class));
+
+ getInstrumentation().runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
+ verify(mockListener, times(1)).onClick(any(View.class));
+
+ verifyNoMoreInteractions(mockListener);
+ }
}
diff --git a/tests/vr/Android.mk b/tests/vr/Android.mk
new file mode 100644
index 0000000..04644a0
--- /dev/null
+++ b/tests/vr/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsVrTestCases
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# Include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/vr/AndroidManifest.xml b/tests/vr/AndroidManifest.xml
new file mode 100644
index 0000000..877d846
--- /dev/null
+++ b/tests/vr/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.vr.cts"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-sdk android:minSdkVersion="14" />
+ <uses-feature android:glEsVersion="0x00020000"/>
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.vr.cts" >
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:hardwareAccelerated="false" >
+
+ <activity
+ android:label="@string/app_name"
+ android:name="android.vr.cts.OpenGLESActivity">
+ </activity>
+ <activity android:name=".CtsActivity"
+ android:label="CtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+</manifest>
diff --git a/tests/vr/AndroidTest.xml b/tests/vr/AndroidTest.xml
new file mode 100644
index 0000000..a687370
--- /dev/null
+++ b/tests/vr/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS VR test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsVrTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.vr.cts" />
+ </test>
+</configuration>
diff --git a/tests/vr/res/drawable-hdpi/ic_launcher.png b/tests/vr/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/tests/vr/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/vr/res/drawable-ldpi/ic_launcher.png b/tests/vr/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/tests/vr/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/tests/vr/res/drawable-mdpi/ic_launcher.png b/tests/vr/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/tests/vr/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/vr/res/layout/main.xml b/tests/vr/res/layout/main.xml
new file mode 100644
index 0000000..fc2dfc1
--- /dev/null
+++ b/tests/vr/res/layout/main.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/vr/res/values/strings.xml b/tests/vr/res/values/strings.xml
new file mode 100644
index 0000000..e87ad4a
--- /dev/null
+++ b/tests/vr/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">CtsVrTestCases</string>
+
+</resources>
diff --git a/tests/vr/src/android/vr/cts/CtsActivity.java b/tests/vr/src/android/vr/cts/CtsActivity.java
new file mode 100644
index 0000000..33fff08
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/CtsActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.app.Activity;
+
+public class CtsActivity extends Activity {
+
+}
diff --git a/tests/vr/src/android/vr/cts/OpenGLESActivity.java b/tests/vr/src/android/vr/cts/OpenGLESActivity.java
new file mode 100644
index 0000000..75eff00
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/OpenGLESActivity.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.opengl.EGL14;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.lang.InterruptedException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+public class OpenGLESActivity extends Activity {
+ private static final String TAG = "OpenGLESActivity";
+
+ public static final String EXTRA_VIEW_INDEX = "viewIndex";
+ public static final String EXTRA_PROTECTED = "protected";
+ public static final String EXTRA_PRIORITY = "priority";
+ public static final String EXTRA_LATCH_COUNT = "latchCount";
+
+
+ // Note that the final extension will use value 0x32C0.
+ public static final int EGL_PROTECTED_CONTENT_EXT = 0x32E0;
+
+ // Context priority enums are not exposed in Java.
+ public static final int EGL_CONTEXT_PRIORITY_LEVEL_IMG = 0x3100;
+
+ OpenGLES20View mView;
+ Renderer mRenderer;
+ int mRendererType;
+ private CountDownLatch mLatch;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+
+ int viewIndex = getIntent().getIntExtra(EXTRA_VIEW_INDEX, -1);
+ int protectedAttribute = getIntent().getIntExtra(EXTRA_PROTECTED, -1);
+ int priorityAttribute = getIntent().getIntExtra(EXTRA_PRIORITY, -1);
+ int latchCount = getIntent().getIntExtra(EXTRA_LATCH_COUNT, 1);
+ mLatch = new CountDownLatch(latchCount);
+ mView = new OpenGLES20View(this, viewIndex, protectedAttribute, priorityAttribute,
+ mLatch);
+
+ setContentView(mView);
+ }
+
+ public int glGetError() {
+ return ((RendererBasicTest)mRenderer).mError;
+ }
+
+ public static void checkEglError(String msg) {
+ boolean failed = false;
+ int error;
+ while ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
+ Log.e(TAG, msg + ": EGL error: 0x" + Integer.toHexString(error));
+ failed = true;
+ }
+ if (failed) {
+ throw new RuntimeException("EGL error encountered (EGL error: 0x" +
+ Integer.toHexString(error) + ")");
+ }
+ }
+
+ public void runOnGlThread(Runnable r) throws Throwable {
+ CountDownLatch fence = new CountDownLatch(1);
+ RunSignalAndCatch wrapper = new RunSignalAndCatch(r, fence);
+
+ mView.queueEvent(wrapper);
+ fence.await(5000, TimeUnit.MILLISECONDS);
+ if (wrapper.error != null) {
+ throw wrapper.error;
+ }
+ }
+
+ public static boolean contextHasAttributeWithValue(int attribute, int value) {
+ int[] values = new int[1];
+ EGL14.eglQueryContext(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+ EGL14.eglGetCurrentContext(), attribute, values, 0);
+ checkEglError("eglQueryContext");
+ return values[0] == value;
+ }
+
+ public static boolean surfaceHasAttributeWithValue(int attribute, int value) {
+ int[] values = new int[1];
+ EGL14.eglQuerySurface(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+ EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW), attribute, values, 0);
+ checkEglError("eglQueryContext");
+ return values[0] == value;
+ }
+
+ public static void setSurfaceAttribute(int attribute, int value) {
+ int[] values = new int[1];
+ EGL14.eglSurfaceAttrib(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+ EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW), attribute, value);
+ checkEglError("eglSurfaceAttrib");
+ }
+
+ public boolean waitForFrameDrawn() {
+ boolean result = false;
+ try {
+ result = mLatch.await(1L, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ // just return false
+ }
+ return result;
+ }
+
+ public boolean supportsVrHighPerformance() {
+ PackageManager pm = getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (mView != null) {
+ mView.onPause();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mView != null) {
+ mView.onResume();
+ }
+ }
+
+ private class RunSignalAndCatch implements Runnable {
+ public Throwable error;
+ private Runnable mRunnable;
+ private CountDownLatch mFence;
+
+ RunSignalAndCatch(Runnable run, CountDownLatch fence) {
+ mRunnable = run;
+ mFence = fence;
+ }
+
+ @Override
+ public void run() {
+ try {
+ mRunnable.run();
+ } catch (Throwable t) {
+ error = t;
+ } finally {
+ mFence.countDown();
+ }
+ }
+ }
+
+ class OpenGLES20View extends GLSurfaceView {
+
+ public OpenGLES20View(Context context, int index, int protectedAttribute,
+ int priorityAttribute, CountDownLatch latch) {
+ super(context);
+ setEGLContextClientVersion(2);
+
+ if (protectedAttribute == 1) {
+ setEGLContextFactory(new ProtectedContextFactory());
+ setEGLWindowSurfaceFactory(new ProtectedWindowSurfaceFactory());
+ } else if (priorityAttribute != 0) {
+ setEGLContextFactory(new PriorityContextFactory(priorityAttribute));
+ }
+
+ if (index == 1) {
+ mRenderer = new RendererBasicTest(latch);
+ } else if (index == 2) {
+ mRenderer = new RendererProtectedTexturesTest(latch);
+ } else if (index == 3) {
+ mRenderer = new RendererRefreshRateTest(latch);
+ } else {
+ throw new RuntimeException();
+ }
+ setRenderer(mRenderer);
+ }
+
+ @Override
+ public void setEGLContextClientVersion(int version) {
+ super.setEGLContextClientVersion(version);
+ }
+ }
+
+ private class PriorityContextFactory implements GLSurfaceView.EGLContextFactory {
+ private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private int mEGLContextClientVersion = 2;
+
+ private int mPriority;
+
+ PriorityContextFactory(int priorityAttribute) {
+ super();
+ mPriority = priorityAttribute;
+ }
+
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
+ int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+ EGL_CONTEXT_PRIORITY_LEVEL_IMG, mPriority, EGL10.EGL_NONE };
+
+ EGLContext context = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
+ attrib_list);
+ if (context == EGL10.EGL_NO_CONTEXT) {
+ Log.e(TAG, "Error creating EGL context.");
+ }
+ checkEglError("eglCreateContext");
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ if (!egl.eglDestroyContext(display, context)) {
+ Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+ }
+ }
+ }
+
+ private class ProtectedContextFactory implements GLSurfaceView.EGLContextFactory {
+ private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private int mEGLContextClientVersion = 2;
+
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
+ int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+ EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE,
+ EGL10.EGL_NONE };
+
+ EGLContext context = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
+ attrib_list);
+ if (context == EGL10.EGL_NO_CONTEXT) {
+ Log.e(TAG, "Error creating EGL context.");
+ }
+ checkEglError("eglCreateContext");
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ if (!egl.eglDestroyContext(display, context)) {
+ Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+ }
+ }
+ }
+
+ private static class ProtectedWindowSurfaceFactory implements GLSurfaceView.EGLWindowSurfaceFactory {
+
+ public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
+ EGLConfig config, Object nativeWindow) {
+ EGLSurface result = null;
+ try {
+ int[] attrib_list = { EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE, EGL10.EGL_NONE };
+ result = egl.eglCreateWindowSurface(display, config, nativeWindow, attrib_list);
+ checkEglError("eglCreateWindowSurface");
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "eglCreateWindowSurface", e);
+ }
+ return result;
+ }
+
+ public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {
+ egl.eglDestroySurface(display, surface);
+ }
+ }
+}
diff --git a/tests/vr/src/android/vr/cts/RendererBasicTest.java b/tests/vr/src/android/vr/cts/RendererBasicTest.java
new file mode 100644
index 0000000..9e1b2a4
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/RendererBasicTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.concurrent.CountDownLatch;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class RendererBasicTest implements GLSurfaceView.Renderer {
+ private String vertexShaderCode =
+ "attribute vec4 vPosition; \n"
+ + "void main(){ \n" +
+ "gl_Position = vPosition; \n"
+ + "} \n";
+
+ private String fragmentShaderCode = "precision mediump float; \n"
+ + "void main(){ \n"
+ + " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n"
+ + "} \n";
+
+
+ FloatBuffer floatBuffer;
+ int mProgram;
+ int maPositionHandle;
+ float[] mColorOne = new float[4];
+
+ int[] mShaderCount = null;
+ int mError;
+
+ // child may need to manipulate them directly
+ protected CountDownLatch mLatch;
+ protected boolean mDrawn = false;
+
+ public RendererBasicTest(CountDownLatch latch) {
+ mLatch = latch;
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ }
+
+ public int loadShader(int type, String shaderCode) {
+ int shader = GLES20.glCreateShader(type);
+ GLES20.glShaderSource(shader, shaderCode);
+ GLES20.glCompileShader(shader);
+ return shader;
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ if (mDrawn) {
+ return;
+ }
+ mDrawn = true;
+ doOnDrawFrame(gl);
+ mLatch.countDown();
+ }
+
+ public void doOnDrawFrame(GL10 gl) {
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
+ GLES20.glUseProgram(mProgram);
+
+ GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
+ false, 12, floatBuffer);
+ GLES20.glEnableVertexAttribArray(maPositionHandle);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
+ mShaderCount = new int[1];
+ int[] shaders = new int[10];
+ GLES20.glGetAttachedShaders(mProgram, 10, mShaderCount, 0, shaders, 0);
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ initShapes();
+ int vertexShaderOne = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
+ int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+ mProgram = GLES20.glCreateProgram();
+ GLES20.glAttachShader(mProgram, vertexShaderOne);
+ GLES20.glAttachShader(mProgram, fragmentShader);
+ GLES20.glLinkProgram(mProgram);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ //do nothing
+ }
+
+ }
+
+ public void initShapes(){
+ float triangleCoords[] = { -0.5f, -0.25f, 0,
+ 0.5f, -0.25f, 0,
+ 0.0f, 0.559016994f, 0};
+ ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleCoords.length * 4);
+ byteBuffer.order(ByteOrder.nativeOrder());
+ floatBuffer = byteBuffer.asFloatBuffer();
+ floatBuffer.put(triangleCoords);
+ floatBuffer.position(0);
+ }
+}
diff --git a/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java b/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
new file mode 100644
index 0000000..e53dfe0
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import java.nio.IntBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+import java.util.concurrent.CountDownLatch;
+
+public class RendererProtectedTexturesTest extends RendererBasicTest {
+
+ private String vertexShaderCode = "attribute vec4 vPosition; \n"
+ + "void main(){ \n"
+ + "gl_Position = vPosition; \n"
+ + "} \n";
+
+ private String fragmentShaderCode = "precision mediump float; \n"
+ + "sampler2D protectedTexture;\n"
+ + "void main(){ \n"
+ + " gl_FragColor = texture2D(protectedTexture, vec2(0.76953125, 0.22265625)); \n"
+ + "} \n";
+
+ // TODO: Update this value when the extension is ratified.
+ public static int GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT = 0x00000016;
+ public static int GL_TEXTURE_PROTECTED_EXT = 0x8BFA;
+
+ private IntBuffer mTexture;
+
+ public RendererProtectedTexturesTest(CountDownLatch latch) {
+ super(latch);
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ initShapes();
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
+ int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+ mProgram = GLES20.glCreateProgram();
+ GLES20.glAttachShader(mProgram, vertexShader);
+ GLES20.glAttachShader(mProgram, fragmentShader);
+ GLES20.glLinkProgram(mProgram);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ //do nothing
+ }
+
+ // Create and bind a protected texture.
+ mTexture = IntBuffer.allocate(1);
+ GLES20.glGenTextures(1, mTexture);
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.get(0));
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL_TEXTURE_PROTECTED_EXT, GLES20.GL_TRUE);
+ int loc = GLES20.glGetUniformLocation(mProgram, "protectedTexture");
+ GLES20.glUniform1i(loc, 2);
+ }
+}
+
diff --git a/tests/vr/src/android/vr/cts/RendererRefreshRateTest.java b/tests/vr/src/android/vr/cts/RendererRefreshRateTest.java
new file mode 100644
index 0000000..30a0e3a
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/RendererRefreshRateTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import java.util.concurrent.CountDownLatch;
+import javax.microedition.khronos.opengles.GL10;
+
+public class RendererRefreshRateTest extends RendererBasicTest {
+
+ public RendererRefreshRateTest(CountDownLatch latch) {
+ super(latch);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ doOnDrawFrame(gl);
+ mLatch.countDown();
+ }
+}
diff --git a/tests/vr/src/android/vr/cts/VrCpuTest.java b/tests/vr/src/android/vr/cts/VrCpuTest.java
new file mode 100644
index 0000000..f015899
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrCpuTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class VrCpuTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+ private CtsActivity mActivity;
+
+ public VrCpuTest() {
+ super(CtsActivity.class);
+ }
+
+ public void testHasAtLeastTwoCores() {
+ mActivity = getActivity();
+ if (mActivity.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+ assertTrue(Runtime.getRuntime().availableProcessors() >= 2);
+ }
+ }
+
+ public void testHasExclusiveCores() {
+ mActivity = getActivity();
+ if (mActivity.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+ int[] excl_cores = Process.getExclusiveCores();
+ assertTrue(excl_cores.length >= 1);
+ }
+ }
+}
diff --git a/tests/vr/src/android/vr/cts/VrDisplayTest.java b/tests/vr/src/android/vr/cts/VrDisplayTest.java
new file mode 100644
index 0000000..6b8b302
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrDisplayTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.content.Context;
+import android.content.Intent;
+import android.opengl.EGL14;
+import android.opengl.GLES32;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import java.nio.IntBuffer;
+
+public class VrDisplayTest extends ActivityInstrumentationTestCase2<OpenGLESActivity> {
+
+ private OpenGLESActivity mActivity;
+
+ public VrDisplayTest() {
+ super(OpenGLESActivity.class);
+ }
+
+ private OpenGLESActivity getGlEsActivity(int latchCount, int viewIndex) {
+ Intent intent = new Intent();
+ intent.putExtra(OpenGLESActivity.EXTRA_LATCH_COUNT, latchCount);
+ intent.putExtra(OpenGLESActivity.EXTRA_VIEW_INDEX, viewIndex);
+ intent.putExtra(OpenGLESActivity.EXTRA_PROTECTED, 0);
+ intent.putExtra(OpenGLESActivity.EXTRA_PRIORITY, 0);
+ setActivityIntent(intent);
+ OpenGLESActivity activity = getActivity();
+ if (latchCount == 1) {
+ assertTrue(activity.waitForFrameDrawn());
+ }
+ return activity;
+ }
+
+ /**
+ * Tests that the refresh rate is at least 60Hz.
+ */
+ public void testRefreshRateIsAtLeast60Hz() throws Throwable {
+ final int NUM_FRAMES = 200;
+ mActivity = getGlEsActivity(NUM_FRAMES, 3);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ long startNanos = System.nanoTime();
+
+ // Render a few hundred frames.
+ int error;
+ while (!mActivity.waitForFrameDrawn());
+ error = mActivity.glGetError();
+ assertEquals(GLES32.GL_NO_ERROR, error);
+ long endNanos = System.nanoTime();
+
+ double fps = NUM_FRAMES / (double)(endNanos - startNanos) * 1e9;
+ assertTrue(fps >= 59.);
+ }
+
+ /**
+ * Tests that the display resolution is at least 1080p.
+ */
+ public void testDisplayResolution() {
+ mActivity = getGlEsActivity(1, 1);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ WindowManager windowManager = (WindowManager)mActivity.getSystemService(
+ Context.WINDOW_SERVICE);
+ DisplayMetrics metrics = new DisplayMetrics();
+
+ // Find the real screen size.
+ int displayWidth;
+ int displayHeight;
+ windowManager.getDefaultDisplay().getRealMetrics(metrics);
+ if (metrics.widthPixels > metrics.heightPixels) {
+ displayWidth = metrics.widthPixels;
+ displayHeight = metrics.heightPixels;
+ } else {
+ displayWidth = metrics.heightPixels;
+ displayHeight = metrics.widthPixels;
+ }
+ assertTrue(displayWidth >= 1920);
+ assertTrue(displayHeight >= 1080);
+ }
+}
diff --git a/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java b/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
new file mode 100644
index 0000000..0641bfb
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.content.Intent;
+import android.opengl.EGL14;
+import android.opengl.GLES32;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.nio.IntBuffer;
+
+public class VrExtensionBehaviorTest extends ActivityInstrumentationTestCase2<OpenGLESActivity> {
+
+ private static final int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
+ private static final int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
+ private static final int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
+
+ private static final int EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID = 0x314C;
+
+ private OpenGLESActivity mActivity;
+
+ public VrExtensionBehaviorTest() {
+ super(OpenGLESActivity.class);
+ }
+
+ private OpenGLESActivity getGlEsActivity(int viewIndex, int createProtected,
+ int priorityAttribute) {
+ Intent intent = new Intent();
+ intent.putExtra(OpenGLESActivity.EXTRA_VIEW_INDEX, viewIndex);
+ intent.putExtra(OpenGLESActivity.EXTRA_PROTECTED, createProtected);
+ intent.putExtra(OpenGLESActivity.EXTRA_PRIORITY, priorityAttribute);
+ setActivityIntent(intent);
+ OpenGLESActivity activity = getActivity();
+ assertTrue(activity.waitForFrameDrawn());
+ return activity;
+ }
+
+ /**
+ * Tests that protected content contexts and surfaces can be created.
+ */
+ public void testProtectedContent() throws Throwable {
+ mActivity = getGlEsActivity(1, 1, 0);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ int error = mActivity.glGetError();
+ assertEquals(GLES32.GL_NO_ERROR, error);
+
+ mActivity.runOnGlThread(new Runnable() {
+ public void run() {
+ // Check that both the context and surface have the right attribute set.
+ assertTrue("Unable to validate protected context",
+ OpenGLESActivity.contextHasAttributeWithValue(
+ OpenGLESActivity.EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE));
+ assertTrue("Unable to validate protected surface",
+ OpenGLESActivity.surfaceHasAttributeWithValue(
+ OpenGLESActivity.EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE));
+ }
+ });
+ }
+
+ /**
+ * Tests that textures can be marked as protected.
+ */
+ public void testProtectedTextures() throws Throwable {
+ mActivity = getGlEsActivity(2, 1, 0);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ int error = mActivity.glGetError();
+ assertEquals(GLES32.GL_NO_ERROR, error);
+
+ mActivity.runOnGlThread(new Runnable() {
+ public void run() {
+ // Check that both the context and surface have the right attribute set.
+ int[] values = new int[1];
+ GLES32.glGetIntegerv(GLES32.GL_CONTEXT_FLAGS, values, 0);
+ assertTrue("Context is not a protected context",
+ (values[0] & RendererProtectedTexturesTest.GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT) != 0);
+
+ values[0] = 0;
+ GLES32.glGetTexParameteriv(GLES32.GL_TEXTURE_2D,
+ RendererProtectedTexturesTest.GL_TEXTURE_PROTECTED_EXT, values, 0);
+ assertEquals("Texture is not marked as protected", GLES32.GL_TRUE, values[0]);
+ }
+ });
+ }
+
+ /**
+ * Tests that context priority can be set to high.
+ */
+ public void testContextPriorityHigh() throws Throwable {
+ runContextPriorityTest(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ }
+
+ /**
+ * Tests that context priority can be set to medium.
+ */
+ public void testContextPriorityMedium() throws Throwable {
+ runContextPriorityTest(EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
+ }
+
+ /**
+ * Tests that context priority can be set to low.
+ */
+ public void testContextPriorityLow() throws Throwable {
+ runContextPriorityTest(EGL_CONTEXT_PRIORITY_LOW_IMG);
+ }
+
+ /**
+ * Tests that context priority can be set to low.
+ */
+ public void testMutableRenderBuffer() throws Throwable {
+
+ mActivity = getGlEsActivity(1, 0, 0);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ int error = mActivity.glGetError();
+ assertEquals(GLES32.GL_NO_ERROR, error);
+
+ mActivity.runOnGlThread(new Runnable() {
+ public void run() {
+ OpenGLESActivity.setSurfaceAttribute(EGL14.EGL_RENDER_BUFFER,
+ EGL14.EGL_SINGLE_BUFFER);
+ OpenGLESActivity.setSurfaceAttribute(EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID,
+ EGL14.EGL_TRUE);
+ swapBuffers();
+ assertTrue("Unable to enable single buffered mode",
+ OpenGLESActivity.contextHasAttributeWithValue(
+ EGL14.EGL_RENDER_BUFFER, EGL14.EGL_SINGLE_BUFFER));
+ assertTrue("Unable to enable single buffered mode",
+ OpenGLESActivity.contextHasAttributeWithValue(
+ EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID, EGL14.EGL_TRUE));
+
+ OpenGLESActivity.setSurfaceAttribute(EGL14.EGL_RENDER_BUFFER,
+ EGL14.EGL_BACK_BUFFER);
+ swapBuffers();
+ assertTrue("Unable to disable single buffered mode",
+ OpenGLESActivity.contextHasAttributeWithValue(
+ EGL14.EGL_RENDER_BUFFER, EGL14.EGL_BACK_BUFFER));
+ }
+ });
+ }
+
+ /**
+ * Runs a context priority test.
+ */
+ private void runContextPriorityTest(int priority) throws Throwable {
+ mActivity = getGlEsActivity(1, 0, priority);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ int error = mActivity.glGetError();
+ assertEquals(GLES32.GL_NO_ERROR, error);
+
+ mActivity.runOnGlThread(new Runnable() {
+ public void run() {
+ assertTrue("Unable to set context priority to " + Integer.toHexString(priority),
+ OpenGLESActivity.contextHasAttributeWithValue(
+ OpenGLESActivity.EGL_CONTEXT_PRIORITY_LEVEL_IMG, priority));
+ }
+ });
+ }
+
+ /**
+ * Swaps EGL buffers.
+ */
+ private void swapBuffers() {
+ EGL14.eglSwapBuffers(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+ EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW));
+ }
+}
diff --git a/tests/vr/src/android/vr/cts/VrSensorsTest.java b/tests/vr/src/android/vr/cts/VrSensorsTest.java
new file mode 100644
index 0000000..1f44def
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrSensorsTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.vr.cts;
+
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests related to sensors and VR.
+ */
+public class VrSensorsTest extends AndroidTestCase {
+ private static final String TAG = "VrSensorsTest";
+
+ /**
+ * Tests creating a protected context.
+ */
+ public void testHiFiSensorsAreSupported() {
+ PackageManager pm = getContext().getPackageManager();
+ assertTrue(!pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE) ||
+ pm.hasSystemFeature(PackageManager.FEATURE_HIFI_SENSORS));
+ }
+}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index 99dc6d1..4b43d39 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -24,7 +24,8 @@
DEVICE_INFO_PERMISSIONS :=
DEVICE_INFO_ACTIVITIES := \
- com.android.compatibility.common.deviceinfo.GlesStubActivity
+ com.android.compatibility.common.deviceinfo.GlesStubActivity \
+ com.android.cts.deviceinfo.CameraDeviceInfo
LOCAL_PACKAGE_NAME := CtsDeviceInfo
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
similarity index 94%
rename from common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
rename to tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
index 2cc4478..41afdb9eb 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.compatibility.common.deviceinfo;
+package com.android.cts.deviceinfo;
import android.content.Context;
import android.graphics.Rect;
@@ -32,6 +32,7 @@
import android.util.SizeF;
import android.util.Range;
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
import com.android.compatibility.common.util.DeviceInfoStore;
import java.lang.reflect.Array;
@@ -415,36 +416,25 @@
store.addResult("profile_qcif", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QCIF));
store.addResult("profile_qvga", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.L) {
- // query camera devices and store each camera's characteristics
- CameraManager cameraManager = (CameraManager)
- getContext().getSystemService(Context.CAMERA_SERVICE);
- try {
- String[] cameraIdList = cameraManager.getCameraIdList();
- store.addResult("num_of_camera", cameraIdList.length);
- if (cameraIdList.length > 0) {
- CameraCharacteristicsStorer charsStorer =
- new CameraCharacteristicsStorer(cameraManager, store);
- store.startArray("per_camera_info");
- for (int i = 0; i < cameraIdList.length; i++) {
- charsStorer.storeCameraInfo(cameraIdList[i]);
- }
- store.endArray(); // per_camera_info
+ CameraManager cameraManager = (CameraManager)
+ getContext().getSystemService(Context.CAMERA_SERVICE);
+ try {
+ String[] cameraIdList = cameraManager.getCameraIdList();
+ store.addResult("num_of_camera", cameraIdList.length);
+ if (cameraIdList.length > 0) {
+ CameraCharacteristicsStorer charsStorer =
+ new CameraCharacteristicsStorer(cameraManager, store);
+ store.startArray("per_camera_info");
+ for (int i = 0; i < cameraIdList.length; i++) {
+ charsStorer.storeCameraInfo(cameraIdList[i]);
}
- } catch (CameraAccessException e) {
- Log.e(TAG,
- "Unable to get camera camera ID list, error: "
- + e.getMessage());
+ store.endArray(); // per_camera_info
}
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
- // Only supports Camera API1
- int numCameras = Camera.getNumberOfCameras();
- store.addResult("num_of_camera", numCameras);
- } else {
- // No Camera number query support
- store.addResult("num_of_camera", 0);
+ } catch (CameraAccessException e) {
+ Log.e(TAG,
+ "Unable to get camera camera ID list, error: "
+ + e.getMessage());
}
-
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
diff --git a/tools/cts-tradefed/res/config/cts-preconditions.xml b/tools/cts-tradefed/res/config/cts-preconditions.xml
index efe8e3f..cc71524 100644
--- a/tools/cts-tradefed/res/config/cts-preconditions.xml
+++ b/tools/cts-tradefed/res/config/cts-preconditions.xml
@@ -51,6 +51,7 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
<option name="src-dir" value="/sdcard/report-log-files/"/>
<option name="dest-dir" value="report-log-files/"/>
+ <option name="temp-dir" value="temp-report-logs/"/>
</target_preparer>
</configuration>
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index ee14116..f1219c1 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -18,7 +18,7 @@
package android.cts.security;
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -37,19 +37,19 @@
private File sepolicyAnalyze;
private File devicePolicyFile;
+ private IBuildInfo mBuild;
+
/**
* A reference to the device under test.
*/
private ITestDevice mDevice;
- private CompatibilityBuildHelper mHelper;
-
/**
* {@inheritDoc}
*/
@Override
public void setBuild(IBuildInfo build) {
- mHelper = new CompatibilityBuildHelper(build);
+ mBuild = build;
}
/**
@@ -63,7 +63,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- sepolicyAnalyze = new File(mHelper.getTestsDir(), "sepolicy-analyze");
+ sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
sepolicyAnalyze.setExecutable(true);
/* obtain sepolicy file from running device */