Merge "Add Wifi status to help diagnose testClearKeyPlaybackCenc failures." into nyc-dev
diff --git a/OldCtsTestCaseList.mk b/OldCtsTestCaseList.mk
index 1c6bd7f..d2eb85b 100644
--- a/OldCtsTestCaseList.mk
+++ b/OldCtsTestCaseList.mk
@@ -155,12 +155,12 @@
CtsAppTestCases \
CtsAppWidgetTestCases \
CtsAssistTestCases \
- CtsAutomotiveTestCases \
CtsBluetoothTestCases \
CtsBrowserTestCases \
CtsCalendarcommon2TestCases \
CtsCallLogTestCases \
CtsCameraTestCases \
+ CtsCarTestCases \
CtsContentTestCases \
CtsDatabaseTestCases \
CtsDisplayTestCases \
@@ -196,6 +196,7 @@
CtsNetTestCasesLegacyApi22 \
CtsNetTestCasesLegacyPermission22 \
CtsNetSecConfigAttributeTestCases \
+ CtsNetSecConfigCleartextTrafficTestCases \
CtsNetSecConfigBasicDebugDisabledTestCases \
CtsNetSecConfigBasicDebugEnabledTestCases \
CtsNetSecConfigBasicDomainConfigTestCases \
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 741baee..c669540 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -597,7 +597,12 @@
for c in cmd["outputSurfaces"]]
formats = [s if s != "jpg" else "jpeg" for s in formats]
else:
+ max_yuv_size = its.objects.get_available_output_sizes(
+ "yuv", self.props)[0]
formats = ['yuv']
+ cmd["outputSurfaces"] = [{"format": "yuv",
+ "width" : max_yuv_size[0],
+ "height": max_yuv_size[1]}]
ncap = len(cmd["captureRequests"])
nsurf = 1 if out_surfaces is None else len(cmd["outputSurfaces"])
# Only allow yuv output to multiple targets
diff --git a/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py b/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py
index b0689c1..682c04a 100644
--- a/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py
+++ b/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py
@@ -14,8 +14,9 @@
import its.device
import its.caps
-import its.objects
import its.image
+import its.objects
+import its.target
import os.path
import pylab
import matplotlib
@@ -47,23 +48,24 @@
raw_format = 'raw10'
elif its.caps.raw12(props):
raw_format = 'raw12'
- else # should not reach here
+ else: # should not reach here
raise its.error.Error('Cannot find available RAW output format')
out_surfaces = [{"format": raw_format},
{"format": "yuv", "width": w, "height": h}]
sens_min, sens_max = props['android.sensor.info.sensitivityRange']
- sens_boost_min, sens_boost_max =
+ sens_boost_min, sens_boost_max = \
props['android.control.postRawSensitivityBoostRange']
- e_targer, s_target =
+
+ e_target, s_target = \
its.target.get_target_exposure_combos(cam)["midSensitivity"]
reqs = []
settings = []
s_boost = sens_boost_min
- while s_boost <= sens_boost_min:
+ while s_boost <= sens_boost_max:
s_raw = int(round(s_target * 100.0 / s_boost))
if s_raw < sens_min or s_raw > sens_max:
continue
@@ -77,9 +79,15 @@
raw_rgb_means = []
yuv_rgb_means = []
- for i,cap in enumerate(caps):
+ raw_caps, yuv_caps = caps
+ if not isinstance(raw_caps, list):
+ raw_caps = [raw_caps]
+ if not isinstance(yuv_caps, list):
+ yuv_caps = [yuv_caps]
+ for i in xrange(len(reqs)):
(s, s_boost) = settings[i]
- raw_cap, yuv_cap = cap
+ raw_cap = raw_caps[i]
+ yuv_cap = yuv_caps[i]
raw_rgb = its.image.convert_capture_to_rgb_image(raw_cap, props=props)
yuv_rgb = its.image.convert_capture_to_rgb_image(yuv_cap)
raw_tile = its.image.get_image_patch(raw_rgb, 0.45,0.45,0.1,0.1)
@@ -90,7 +98,7 @@
"%s_raw_s=%04d_boost=%04d.jpg" % (NAME,s,s_boost))
its.image.write_image(yuv_tile,
"%s_yuv_s=%04d_boost=%04d.jpg" % (NAME,s,s_boost))
- print "s=%d, s_boost=%d: raw_means %s, yuv_means %d"%(
+ print "s=%d, s_boost=%d: raw_means %s, yuv_means %s"%(
s,s_boost,raw_rgb_means[-1], yuv_rgb_means[-1])
xs = range(len(reqs))
@@ -125,7 +133,7 @@
yuv_thres_max = 1 + RATIO_THRESHOLD
for rgb in range(3):
vals = [val[rgb] for val in yuv_rgb_means]
- mean = sum(vals) / len(vales)
+ mean = sum(vals) / len(vals)
print "%s channel vals %s mean %f"%(rgb_str[rgb], vals, mean)
for step in range(len(reqs)):
ratio = vals[step] / mean
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 13bc98e..ee98618 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -460,8 +460,7 @@
</activity>
<activity android:name=".net.ConnectivityScreenOffTestActivity"
- android:label="@string/network_screen_off_test"
- android:screenOrientation="portrait">
+ android:label="@string/network_screen_off_test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
@@ -1521,6 +1520,10 @@
</intent-filter>
</activity-alias>
+ <activity android:name=".managedprovisioning.OrganizationInfoTestActivity"
+ android:label="@string/provisioning_byod_organization_info">
+ </activity>
+
<activity android:name=".managedprovisioning.PolicyTransparencyTestListActivity"
android:label="@string/device_profile_owner_policy_transparency_test">
<intent-filter>
@@ -1625,6 +1628,7 @@
<action android:name="com.android.cts.verifier.managedprovisioning.CLEAR_NOTIFICATION" />
<action android:name="com.android.cts.verifier.managedprovisioning.TEST_SELECT_WORK_CHALLENGE" />
<action android:name="com.android.cts.verifier.managedprovisioning.TEST_CONFIRM_WORK_CREDENTIALS" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.TEST_ORGANIZATION_INFO" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>
diff --git a/apps/CtsVerifier/jni/audio_loopback/Android.mk b/apps/CtsVerifier/jni/audio_loopback/Android.mk
index 3dfbc34..b302f44 100644
--- a/apps/CtsVerifier/jni/audio_loopback/Android.mk
+++ b/apps/CtsVerifier/jni/audio_loopback/Android.mk
@@ -23,6 +23,7 @@
LOCAL_PRELINK_MODULE := false
LOCAL_LDFLAGS := -Wl,--hash-style=sysv
-LOCAL_CFLAGS := -DSTDC_HEADERS
+LOCAL_CFLAGS := -DSTDC_HEADERS \
+ -Werror -Wall
include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/jni/audio_loopback/sles.cpp b/apps/CtsVerifier/jni/audio_loopback/sles.cpp
index 7859d35..b0b683b 100644
--- a/apps/CtsVerifier/jni/audio_loopback/sles.cpp
+++ b/apps/CtsVerifier/jni/audio_loopback/sles.cpp
@@ -40,14 +40,14 @@
if (ppSles != NULL) {
sles_data * pSles = (sles_data*) calloc(1, sizeof (sles_data));
- SLES_PRINTF("malloc %d bytes at %p",sizeof(sles_data), pSles);
+ SLES_PRINTF("malloc %zu bytes at %p", sizeof(sles_data), pSles);
*ppSles = pSles;
if (pSles != NULL)
{
SLES_PRINTF("creating server. Sampling rate =%d, frame count = %d",samplingRate,
frameCount);
status = slesCreateServer(pSles, samplingRate, frameCount, micSource);
- SLES_PRINTF("slesCreateServer =%d",status);
+ SLES_PRINTF("slesCreateServer =%d", status);
}
}
return status;
@@ -260,6 +260,7 @@
// char **freeBuffers;
// Buffer indices
+/*
pSles->rxFront; // oldest recording
pSles->rxRear; // next to be recorded
pSles->txFront; // oldest playing
@@ -268,9 +269,8 @@
pSles->freeRear; // next to be freed
pSles->fifo; //(*)
+*/
pSles->fifo2Buffer = NULL;
- pSles->recorderBufferQueue;
- pSles->playerBufferQueue;
// compute total free buffers as -r plus -t
pSles->freeBufCount = pSles->rxBufCount + pSles->txBufCount;
@@ -325,7 +325,6 @@
SLresult result;
// create engine
- pSles->engineObject;
result = slCreateEngine(&(pSles->engineObject), 0, NULL, 0, NULL, NULL);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
result = (*(pSles->engineObject))->Realize(pSles->engineObject, SL_BOOLEAN_FALSE);
@@ -336,7 +335,6 @@
ASSERT_EQ(SL_RESULT_SUCCESS, result);
// create output mix
- pSles->outputmixObject;
result = (*engineEngine)->CreateOutputMix(engineEngine, &(pSles->outputmixObject), 0, NULL,
NULL);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
diff --git a/apps/CtsVerifier/res/layout/organization_info.xml b/apps/CtsVerifier/res/layout/organization_info.xml
new file mode 100644
index 0000000..320fb8c
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/organization_info.xml
@@ -0,0 +1,70 @@
+<?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:id="@+id/root_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:id="@+id/provisioning_byod_organization_info_instructions"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:text="@string/provisioning_byod_organization_info_instructions"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <EditText android:id="@+id/organization_name_edit_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:hint="@string/provisioning_byod_organization_name_hint"
+ android:gravity="top|start"
+ android:windowSoftInputMode="adjustPan"
+ android:padding="16dp"
+ android:layout_weight="1"/>
+ <EditText android:id="@+id/organization_color_edit_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:hint="@string/provisioning_byod_organization_color_hint"
+ android:gravity="top|start"
+ android:digits="#0123456789abcdefABCDEF"
+ android:inputType="textCapCharacters"
+ android:windowSoftInputMode="adjustPan"
+ android:padding="16dp"
+ android:layout_weight="1" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button android:id="@+id/organization_info_set_button"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/provisioning_byod_set_organization_info_button_text"
+ android:layout_weight="1"/>
+ <Button android:id="@+id/go_button"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/go_button_text"
+ android:layout_weight="1"/>
+ </LinearLayout>
+
+ <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index cbd7f6b..0dbb16f 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1291,14 +1291,14 @@
<string name="keychain_reset">Reset</string>
<string name="keychain_skip">Skip</string>
<string name="keychain_setup_desc">The first step sets up an internal KeyStore and generates credentials to use for the remainder of the test.\n\n
- Touch \'Next\' to begin.</string>
- <string name="keychain_install_desc">Credentials generated. Touch \'Next\' to install them to the system keychain.\n\n
+ Tap \'Next\' to begin.</string>
+ <string name="keychain_install_desc">Credentials generated. Tap \'Next\' to install them to the system keychain.\n\n
The container for the credentials will not be protected with a password; if prompted for one, leave that field blank.\n\n
During installation you may be prompted for a name - accept the default suggestion.\n\n
In the case that these credentials were already installed, you may skip this step.</string>
<string name="keychain_https_desc">The last test involves setting up an HTTPS connection using credentials from the KeyChain.\n\n
You should be prompted to select credentials; choose the ones you just installed in the previous step.</string>
- <string name="keychain_reset_desc">Before marking this test as passed, touch \'Next\' to open security settings and reset the following items:\n
+ <string name="keychain_reset_desc">Before marking this test as passed, tap \'Next\' to open security settings and reset the following items:\n
1. Clear device credentials.\n
2. Change the lock screen type to \'None\'.</string>
@@ -1921,6 +1921,20 @@
3. Check that the work notification has disappeared.\n
4. Set work mode to on.\n
</string>
+ <string name="provisioning_byod_organization_info">Organization Info</string>
+ <string name="provisioning_byod_organization_name_hint">Name</string>
+ <string name="provisioning_byod_organization_color_hint">#FF00FF</string>
+ <string name="provisioning_byod_set_organization_info_button_text">Set</string>
+ <string name="provisioning_byod_organization_info_instructions">
+ This test verifies that the Organization Info was set correctly.
+ You can only do this test after you have done "select work challenge" test.\n
+ 1. Enter your organization name.\n
+ 2. Enter a valid color code.\n
+ 3. Press the Set button to set organization Info.\n
+ 4. Press the Go button to open a dialog to confirm work credentials.\n
+ 5. Verify that the background color of the resulting dialog is as set by you.\n
+ 6. Verify that the header text has organization name as set by you.\n
+ </string>
<!-- Strings for DeviceOwnerProvisioningTest -->
<string name="provisioning_device_owner">Device Owner Provisioning</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index e00d287..9b5df85 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -94,6 +94,7 @@
private DialogTestListItem mConfirmWorkCredentials;
private TestListItem mVpnTest;
private TestListItem mDisallowAppsControlTest;
+ private TestListItem mOrganizationInfoTest;
private TestListItem mPolicyTransparencyTest;
public ByodFlowTestActivity() {
@@ -374,6 +375,12 @@
R.string.provisioning_byod_confirm_work_credentials_description,
new Intent(ByodHelperActivity.ACTION_TEST_CONFIRM_WORK_CREDENTIALS));
+ mOrganizationInfoTest = TestListItem.newTest(this,
+ R.string.provisioning_byod_organization_info,
+ OrganizationInfoTestActivity.class.getName(),
+ new Intent(this, OrganizationInfoTestActivity.class),
+ null);
+
final Intent policyTransparencyTestIntent = new Intent(this,
PolicyTransparencyTestListActivity.class);
policyTransparencyTestIntent.putExtra(
@@ -418,6 +425,7 @@
adapter.add(mTurnOffWorkNotifications);
adapter.add(mSelectWorkChallenge);
adapter.add(mConfirmWorkCredentials);
+ adapter.add(mOrganizationInfoTest);
adapter.add(mPolicyTransparencyTest);
if (canResolveIntent(new Intent(Settings.ACTION_APPLICATION_SETTINGS))) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index cfb42fd..b9e6541 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -135,6 +135,9 @@
public static final String ACTION_TEST_CONFIRM_WORK_CREDENTIALS =
"com.android.cts.verifier.managedprovisioning.TEST_CONFIRM_WORK_CREDENTIALS";
+ public static final String ACTION_SET_ORGANIZATION_INFO =
+ "com.android.cts.verifier.managedprovisioning.TEST_ORGANIZATION_INFO";
+
public static final int RESULT_FAILED = RESULT_FIRST_USER;
private static final int REQUEST_INSTALL_PACKAGE = 2;
@@ -324,6 +327,16 @@
(KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
Intent launchIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
startActivity(launchIntent);
+ } else if (ACTION_SET_ORGANIZATION_INFO.equals(action)) {
+ if(intent.hasExtra(OrganizationInfoTestActivity.EXTRA_ORGANIZATION_NAME)) {
+ final String organizationName = intent
+ .getStringExtra(OrganizationInfoTestActivity.EXTRA_ORGANIZATION_NAME);
+ mDevicePolicyManager.setOrganizationName(mAdminReceiverComponent, organizationName);
+ }
+ final int organizationColor = intent.getIntExtra(
+ OrganizationInfoTestActivity.EXTRA_ORGANIZATION_COLOR,
+ mDevicePolicyManager.getOrganizationColor(mAdminReceiverComponent));
+ mDevicePolicyManager.setOrganizationColor(mAdminReceiverComponent, organizationColor);
}
// This activity has no UI and is only used to respond to CtsVerifier in the primary side.
finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index d7d9b71..e4250f0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -102,6 +102,7 @@
filter.addAction(VpnTestActivity.ACTION_VPN);
filter.addAction(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE);
filter.addAction(ByodHelperActivity.ACTION_TEST_CONFIRM_WORK_CREDENTIALS);
+ filter.addAction(ByodHelperActivity.ACTION_SET_ORGANIZATION_INFO);
filter.addAction(SetSupportMessageActivity.ACTION_SET_SUPPORT_MSG);
filter.addAction(CommandReceiverActivity.ACTION_EXECUTE_COMMAND);
dpm.addCrossProfileIntentFilter(getWho(context), filter,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.java
new file mode 100644
index 0000000..3fb7120
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.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.verifier.managedprovisioning;
+
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+/**
+ * Test class to verify Organization Info.
+ */
+public class OrganizationInfoTestActivity extends PassFailButtons.Activity
+ implements View.OnClickListener {
+
+ public static final String EXTRA_ORGANIZATION_NAME = "extra_organization_name";
+ public static final String EXTRA_ORGANIZATION_COLOR = "extra_organization_color";
+
+ private int mOrganizationColor;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.organization_info);
+ setPassFailButtonClickListeners();
+ setButtonClickListeners();
+ }
+
+ private void setButtonClickListeners() {
+ findViewById(R.id.organization_info_set_button).setOnClickListener(this);
+ findViewById(R.id.go_button).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view.getId() == R.id.organization_info_set_button) {
+ EditText organizationNameEditText = (EditText) findViewById(
+ R.id.organization_name_edit_text);
+ Intent intent = new Intent(ByodHelperActivity.ACTION_SET_ORGANIZATION_INFO);
+ intent.putExtra(EXTRA_ORGANIZATION_NAME, organizationNameEditText.getText().toString());
+ if (isOrganizationColorSet()) {
+ intent.putExtra(EXTRA_ORGANIZATION_COLOR, mOrganizationColor);
+ }
+ startActivity(intent);
+ } else if (view.getId() == R.id.go_button) {
+ Intent intent = new Intent(ByodHelperActivity.ACTION_TEST_CONFIRM_WORK_CREDENTIALS);
+ startActivity(intent);
+ }
+ }
+
+ private boolean isOrganizationColorSet() {
+ EditText organizationColorEditText = (EditText) findViewById(
+ R.id.organization_color_edit_text);
+ try {
+ mOrganizationColor = Color.parseColor(organizationColorEditText.getText().toString());
+ } catch (Exception e) {
+ Toast.makeText(this, "Not a valid Color value", Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java
index e529b67..6109893 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -89,7 +90,7 @@
private final ScreenAndPlugStateReceiver mReceiver;
private final IntentFilter mIntentFilter;
- private boolean mHasBattery;
+ private boolean mWaitForPowerDisconnected;
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
@@ -159,10 +160,11 @@
null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
// Whether or not this device (currently) has a battery.
- mHasBattery = batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+ mWaitForPowerDisconnected =
+ batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false) && !isLeanback();
// Check if the device is already on battery power.
- if (mHasBattery) {
+ if (mWaitForPowerDisconnected) {
BatteryManager battMgr = (BatteryManager) getSystemService(Context.BATTERY_SERVICE);
if (!battMgr.isCharging()) {
mState.setPowerDisconnected();
@@ -286,7 +288,8 @@
/**
* TODO(ek): Evaluate reworking the code roughly as follows:
- * - Move all the shared state here, including mHasBattery (and mTestingThread).
+ * - Move all the shared state here, including mWaitForPowerDisconnected
+ * (and mTestingThread).
* - Move from synchronizing on mLock to synchronizing on this since the
* AppState object is final, and delete mLock.
* - Synchronize the methods below, and add some required new methods.
@@ -311,7 +314,9 @@
void setPowerConnected() { mPowerDisconnectTime = 0; }
void setPowerDisconnected() { mPowerDisconnectTime = SystemClock.elapsedRealtime(); }
- boolean validPowerStateForTesting() { return !mHasBattery || (mPowerDisconnectTime > 0); }
+ boolean validPowerStateForTesting() {
+ return !mWaitForPowerDisconnected || (mPowerDisconnectTime > 0);
+ }
}
class ScreenAndPlugStateReceiver extends BroadcastReceiver {
@@ -453,7 +458,7 @@
continue;
}
- if (mHasBattery) {
+ if (mWaitForPowerDisconnected) {
final long delta = SystemClock.elapsedRealtime() - localState.mPowerDisconnectTime;
if (delta < MIN_POWER_DISCONNECT_MS) {
nextSleepDurationMs = (int) (MIN_POWER_DISCONNECT_MS - delta);
@@ -629,4 +634,9 @@
return new HttpResult(rcode, msg);
}
+
+ private boolean isLeanback() {
+ final PackageManager pm = this.getPackageManager();
+ return (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK));
+ }
}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java
index e0f3eab..9f1bda5 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java
@@ -27,8 +27,12 @@
public class DeviceInfoStore extends InfoStore {
- private final File mJsonFile;
- private JsonWriter mJsonWriter = null;
+ protected File mJsonFile;
+ protected JsonWriter mJsonWriter = null;
+
+ public DeviceInfoStore() {
+ mJsonFile = null;
+ }
public DeviceInfoStore(File file) throws Exception {
mJsonFile = file;
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 d87ebbc..57b9e3e 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
@@ -18,12 +18,14 @@
import android.app.Instrumentation;
import android.os.Bundle;
+import android.os.Environment;
import android.util.Log;
import com.android.compatibility.common.util.ReportLog;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.File;
import java.io.IOException;
/**
@@ -35,12 +37,87 @@
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";
+ 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;
+ private ReportLogDeviceInfoStore store;
+
+ public DeviceReportLog() {
+ this(DEFAULT_REPORT_LOG_NAME, DEFAULT_STREAM_NAME);
+ }
+
+ public DeviceReportLog(String reportLogName) {
+ this(reportLogName, DEFAULT_STREAM_NAME);
+ }
+
+ public DeviceReportLog(String reportLogName, String streamName) {
+ super(reportLogName, streamName);
+ try {
+ final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ throw new IOException("External storage is not mounted");
+ } else if (!dir.mkdirs() && !dir.isDirectory()) {
+ throw new IOException("Cannot create directory for device info files");
+ } else {
+ File jsonFile = new File(dir, mReportLogName + ".reportlog.json");
+ store = new ReportLogDeviceInfoStore(jsonFile, mStreamName);
+ store.open();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not create report log file.");
+ }
+ }
+
+ @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) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ @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) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ @Override
+ public void addValues(String source, String message, double[] values, ResultType type,
+ ResultUnit unit) {
+ super.addValues(source, message, values, type, unit);
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ @Override
+ public void addValues(String message, double[] values, ResultType type,
+ ResultUnit unit) {
+ super.addValues(message, values, type, unit);
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
public void submit(Instrumentation instrumentation) {
Log.i(TAG, "Submit");
try {
+ store.close();
Bundle output = new Bundle();
output.putString(RESULT, serialize(this));
instrumentation.sendStatus(INST_STATUS_IN_PROGRESS, output);
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
new file mode 100644
index 0000000..67e6c39
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.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 android.util.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 ReportLogDeviceInfoStore extends DeviceInfoStore {
+
+ private final String mStreamName;
+
+ public ReportLogDeviceInfoStore(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/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 7dbece0..b8887cf 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
@@ -17,9 +17,17 @@
import android.app.Instrumentation;
import android.os.Bundle;
+import android.os.Environment;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.lang.StringBuilder;
import junit.framework.TestCase;
+import org.json.JSONObject;
+
/**
* Tests for {@line DeviceReportLog}.
*/
@@ -50,6 +58,20 @@
private static final double TEST_VALUE_2 = 5;
private static final ResultType TEST_TYPE_2 = ResultType.LOWER_BETTER;
private static final ResultUnit TEST_UNIT_2 = ResultUnit.COUNT;
+ private static final String TEST_MESSAGE_3 = "Sample";
+ private static final double TEST_VALUE_3 = 7;
+ private static final ResultType TEST_TYPE_3 = ResultType.LOWER_BETTER;
+ private static final ResultUnit TEST_UNIT_3 = ResultUnit.COUNT;
+ private static final String TEST_MESSAGE_4 = "Message";
+ private static final double TEST_VALUE_4 = 9;
+ private static final ResultType TEST_TYPE_4 = ResultType.LOWER_BETTER;
+ private static final ResultUnit TEST_UNIT_4 = ResultUnit.COUNT;
+ private static final String REPORT_NAME_1 = "TestReport1";
+ private static final String REPORT_NAME_2 = "TestReport2";
+ private static final String STREAM_NAME_1 = "SampleStream1";
+ private static final String STREAM_NAME_2 = "SampleStream2";
+ private static final String STREAM_NAME_3 = "SampleStream3";
+ private static final String STREAM_NAME_4 = "SampleStream4";
public void testSubmit() throws Exception {
DeviceReportLog log = new DeviceReportLog();
@@ -64,4 +86,69 @@
ReportLog result = ReportLog.parse(metrics);
assertNotNull("Metrics could not be decoded", result);
}
+
+ 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());
+
+ // Remove files from earlier possible runs.
+ File[] files = dir.listFiles();
+ for (File file : files) {
+ file.delete();
+ }
+
+ TestInstrumentation inst = new TestInstrumentation();
+
+ DeviceReportLog log1 = new DeviceReportLog(REPORT_NAME_1, STREAM_NAME_1);
+ log1.addValue(TEST_MESSAGE_1, TEST_VALUE_1, TEST_TYPE_1, TEST_UNIT_1);
+ log1.setSummary(TEST_MESSAGE_1, TEST_VALUE_1, TEST_TYPE_1, TEST_UNIT_1);
+ log1.submit(inst);
+
+ DeviceReportLog log2 = new DeviceReportLog(REPORT_NAME_1, STREAM_NAME_2);
+ log2.addValue(TEST_MESSAGE_2, TEST_VALUE_2, TEST_TYPE_2, TEST_UNIT_2);
+ log2.setSummary(TEST_MESSAGE_2, TEST_VALUE_2, TEST_TYPE_2, TEST_UNIT_2);
+ log2.submit(inst);
+
+ DeviceReportLog log3 = new DeviceReportLog(REPORT_NAME_2, STREAM_NAME_3);
+ log3.addValue(TEST_MESSAGE_3, TEST_VALUE_3, TEST_TYPE_3, TEST_UNIT_3);
+ log3.setSummary(TEST_MESSAGE_3, TEST_VALUE_3, TEST_TYPE_3, TEST_UNIT_3);
+ log3.submit(inst);
+
+ DeviceReportLog log4 = new DeviceReportLog(REPORT_NAME_2, STREAM_NAME_4);
+ log4.addValue(TEST_MESSAGE_4, TEST_VALUE_4, TEST_TYPE_4, TEST_UNIT_4);
+ log4.setSummary(TEST_MESSAGE_4, TEST_VALUE_4, TEST_TYPE_4, TEST_UNIT_4);
+ log4.submit(inst);
+
+ File jsonFile1 = new File(dir, REPORT_NAME_1 + ".reportlog.json");
+ File jsonFile2 = new File(dir, REPORT_NAME_2 + ".reportlog.json");
+ assertTrue("Report Log missing", jsonFile1.exists());
+ assertTrue("Report Log missing", jsonFile2.exists());
+
+ BufferedReader jsonReader = new BufferedReader(new FileReader(jsonFile1));
+ StringBuilder metricsBuilder = new StringBuilder();
+ String line;
+ while ((line = jsonReader.readLine()) != null) {
+ metricsBuilder.append(line);
+ }
+ String metrics = metricsBuilder.toString().trim();
+ JSONObject jsonObject = new JSONObject(metrics);
+ assertTrue("Incorrect metrics",
+ jsonObject.getJSONObject(STREAM_NAME_1).getDouble(TEST_MESSAGE_1) == TEST_VALUE_1);
+ assertTrue("Incorrect metrics",
+ jsonObject.getJSONObject(STREAM_NAME_2).getDouble(TEST_MESSAGE_2) == TEST_VALUE_2);
+
+ jsonReader = new BufferedReader(new FileReader(jsonFile2));
+ metricsBuilder = new StringBuilder();
+ while ((line = jsonReader.readLine()) != null) {
+ metricsBuilder.append(line);
+ }
+ metrics = metricsBuilder.toString().trim();
+ jsonObject = new JSONObject(metrics);
+ assertTrue("Incorrect metrics",
+ jsonObject.getJSONObject(STREAM_NAME_3).getDouble(TEST_MESSAGE_3) == TEST_VALUE_3);
+ assertTrue("Incorrect metrics",
+ jsonObject.getJSONObject(STREAM_NAME_4).getDouble(TEST_MESSAGE_4) == TEST_VALUE_4);
+ }
}
diff --git a/common/host-side/tradefed/res/config/common-compatibility-config.xml b/common/host-side/tradefed/res/config/common-compatibility-config.xml
index 7f3f76a..1b40f16 100644
--- a/common/host-side/tradefed/res/config/common-compatibility-config.xml
+++ b/common/host-side/tradefed/res/config/common-compatibility-config.xml
@@ -17,6 +17,8 @@
<device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
<build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
<test class="com.android.compatibility.common.tradefed.testtype.CompatibilityTest" />
- <logger class="com.android.tradefed.log.FileLogger" />
+ <logger class="com.android.tradefed.log.FileLogger">
+ <option name="log-level-display" value="WARN" />
+ </logger>
<result_reporter class="com.android.compatibility.common.tradefed.result.ResultReporter" />
</configuration>
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 28596d3..18695fe 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
@@ -127,7 +127,7 @@
long time = System.currentTimeMillis();
String dirSuffix = getDirSuffix(time);
if (mRetrySessionId != null) {
- Log.d(mDeviceSerial, String.format("Retrying session %d", mRetrySessionId));
+ CLog.d("[%s] Retrying session %d", mDeviceSerial, mRetrySessionId);
List<IInvocationResult> results = null;
try {
results = ResultHandler.getResults(mBuildHelper.getResultsDir());
@@ -327,6 +327,7 @@
File resultFile = ResultHandler.writeResults(mBuildHelper.getSuiteName(),
mBuildHelper.getSuiteVersion(), mBuildHelper.getSuitePlan(), mResult,
mResultDir, mStartTime, elapsedTime + mStartTime, mReferenceUrl);
+ logResult("Result saved at: %s", resultFile.getCanonicalPath());
copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
copyFormattingFiles(mResultDir);
zipResults(mResultDir);
@@ -336,8 +337,8 @@
fis = new FileInputStream(resultFile);
mLogSaver.saveLogData("log-result", LogDataType.XML, fis);
} catch (IOException ioe) {
- Log.e(mDeviceSerial, "error saving XML with log saver");
- Log.e(mDeviceSerial, ioe);
+ CLog.e("[%s] error saving XML with log saver", mDeviceSerial);
+ CLog.e(ioe);
} finally {
StreamUtil.close(fis);
}
@@ -347,10 +348,12 @@
logResult("Result Server Response: %d",
mUploader.uploadResult(resultFile, mReferenceUrl));
} catch (IOException ioe) {
- Log.e(mDeviceSerial, ioe);
+ CLog.e("[%s] IOException while uploading result.", mDeviceSerial);
+ CLog.e(ioe);
}
}
} catch (IOException | XmlPullParserException e) {
+ CLog.e("[%s] Exception while saving result XML.", mDeviceSerial);
CLog.e(e);
}
}
@@ -477,10 +480,11 @@
}
private void logResult(String format, Object... args) {
+ format = String.format("[%s] %s", mDeviceSerial, format);
if (mQuietOutput) {
CLog.i(format, args);
} else {
- Log.logAndDisplay(LogLevel.INFO, mDeviceSerial, String.format(format, args));
+ CLog.logAndDisplay(LogLevel.INFO, format, args);
}
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
index 916e8ec..33ee5d8 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
@@ -26,7 +26,6 @@
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetCleaner;
@@ -83,7 +82,9 @@
return;
}
try {
- if (!instrument(device, buildInfo)) {
+ if (instrument(device, buildInfo)) {
+ logInfo("Target preparation successful");
+ } else {
throw new TargetSetupError("Not all target preparation steps completed");
}
} catch (FileNotFoundException e) {
@@ -106,8 +107,8 @@
try {
instrument(device, buildInfo);
} catch (FileNotFoundException e1) {
- CLog.e("Couldn't find apk to instrument");
- CLog.e(e1);
+ logError("Couldn't find apk to instrument");
+ logError(e1);
}
}
@@ -122,6 +123,12 @@
throw new FileNotFoundException(String.format("%s not found", mApkFileName));
}
+ if (device.getAppPackageInfo(mPackageName) != null) {
+ logInfo("Package %s already present on the device, uninstalling ...", mPackageName);
+ device.uninstallPackage(mPackageName);
+ }
+
+ logInfo("Instrumenting package %s:", mPackageName);
AndroidJUnitTest instrTest = new AndroidJUnitTest();
instrTest.setDevice(device);
instrTest.setInstallFile(apkFile);
@@ -134,7 +141,7 @@
for (TestIdentifier test : testFailures.keySet()) {
success = false;
String trace = testFailures.get(test);
- CLog.e("Target preparation step %s failed.\n%s", test.getTestName(), trace);
+ logError("Target preparation step %s failed.\n%s", test.getTestName(), trace);
}
}
return success;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
index 0178bab..a0b8faf 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
@@ -18,7 +18,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
-import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -63,8 +62,9 @@
BUILD_KEYS.put("build_version_security_patch", "ro.build.version.security_patch");
}
- @Option(name = CompatibilityTest.SKIP_DEVICE_INFO_OPTION, description =
- "Whether device info collection should be skipped")
+ @Option(name = CompatibilityTest.SKIP_DEVICE_INFO_OPTION,
+ shortName = 'd',
+ description = "Whether device info collection should be skipped")
private boolean mSkipDeviceInfo = false;
@Option(name= "src-dir", description = "The directory to copy to the results dir")
@@ -91,10 +91,6 @@
getDeviceInfoFiles(device, buildInfo);
}
- private void addBuildInfo(ITestDevice device, IBuildInfo buildInfo, String key, String value)
- throws DeviceNotAvailableException {
- }
-
private void getDeviceInfoFiles(ITestDevice device, IBuildInfo buildInfo) {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
try {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
index cea3136..94bc64f 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
@@ -51,6 +51,7 @@
return; // skip this precondition if required location feature is not present
}
+ logInfo("Verifying location setting");
mSettingName = LOCATION_SETTING;
mSettingType = SettingsPreparer.SettingType.SECURE;
mExpectedSettingValues.add(NETWORK);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
index 5c94c27..fc25e03 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
@@ -17,24 +17,29 @@
package com.android.compatibility.common.tradefed.targetprep;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.TargetSetupError;
/**
- * An {@link ITargetPreparer} that performs checks and/or tasks to ensure the
+ * An {@link ITargetPreparer} that performs checks and/or tasks to ensure the
* the device is ready to run the test suite.
*/
public abstract class PreconditionPreparer implements ITargetPreparer {
- @Option(name = CompatibilityTest.SKIP_PRECONDITIONS_OPTION, description =
- "Whether preconditions should be skipped")
+ @Option(name = CompatibilityTest.SKIP_PRECONDITIONS_OPTION,
+ shortName = 'o',
+ description = "Whether preconditions should be skipped")
private boolean mSkipPreconditions = false;
+ protected final String LOG_TAG = getClass().getSimpleName();
+
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
@@ -45,4 +50,35 @@
public abstract void run(ITestDevice device, IBuildInfo buildInfo)
throws TargetSetupError, BuildError, DeviceNotAvailableException;
+
+ protected void logInfo(String info) {
+ LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, info);
+ }
+
+ protected void logInfo(String infoFormat, Object... args) {
+ LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, String.format(infoFormat, args));
+ }
+
+ protected void logWarning(String warning) {
+ LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG, warning);
+ }
+
+ protected void logWarning(String warningFormat, Object... args) {
+ LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG, String.format(warningFormat, args));
+ }
+
+ protected void logError(String error) {
+ LogUtil.printLog(Log.LogLevel.ERROR, LOG_TAG, error);
+ }
+
+ protected void logError(String errorFormat, Object... args) {
+ LogUtil.printLog(Log.LogLevel.ERROR, LOG_TAG, String.format(errorFormat, args));
+ }
+
+ protected void logError(Throwable t) {
+ if (t != null) {
+ Log.e(LOG_TAG, t);
+ }
+ }
+
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
index 4d00ea5..79f19d0 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
@@ -15,13 +15,11 @@
*/
package com.android.compatibility.common.tradefed.targetprep;
-import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -48,11 +46,11 @@
@Override
public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
+
String propertyValue = device.getProperty(mPropertyName);
if (propertyValue == null) {
- LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG, String.format(
- "Property \"%s\" not found on device, cannot verify value \"%s\" ",
- mPropertyName, mExpectedPropertyValue));
+ logWarning("Property \"%s\" not found on device, cannot verify value \"%s\" ",
+ mPropertyName, mExpectedPropertyValue);
return;
}
@@ -63,7 +61,7 @@
if(mThrowError) {
throw new TargetSetupError(msg);
} else {
- LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG, msg);
+ logWarning(msg);
}
}
}
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
new file mode 100644
index 0000000..c786ef4
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
@@ -0,0 +1,101 @@
+/*
+ * 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.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * An {@link ITargetCleaner} that prepares and pulls report logs.
+ */
+public class ReportLogCollector implements ITargetCleaner {
+
+ @Option(name= "src-dir", description = "The directory to copy to the results dir")
+ private String mSrcDir;
+
+ @Option(name = "dest-dir", description = "The directory under the result to store the files")
+ private String mDestDir;
+
+ public ReportLogCollector() {
+ }
+
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+ prepareReportLogContainers(device, buildInfo);
+ }
+
+ private void addBuildInfo(ITestDevice device, IBuildInfo buildInfo, String key, String value)
+ throws DeviceNotAvailableException {
+ }
+
+ private void prepareReportLogContainers(ITestDevice device, IBuildInfo buildInfo) {
+ 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;
+ }
+ } catch (FileNotFoundException fnfe) {
+ fnfe.printStackTrace();
+ }
+ }
+
+ @Override
+ public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) {
+ // Pull report log files from device.
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+ try {
+ File resultDir = buildHelper.getResultDir();
+ String resultPath = resultDir.getAbsolutePath();
+ pull(device, mSrcDir, resultPath);
+ } catch (FileNotFoundException fnfe) {
+ fnfe.printStackTrace();
+ }
+ }
+
+ private void pull(ITestDevice device, String src, String dest) {
+ String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(), src, dest);
+ try {
+ Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
+ if (p.waitFor() != 0) {
+ CLog.e("Failed to run %s", command);
+ }
+ } catch (Exception e) {
+ CLog.e("Caught exception during pull.");
+ CLog.e(e);
+ }
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
index f21ef39..d4c9d54 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
@@ -95,6 +95,8 @@
String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
// only change unexpected setting value
if (!mExpectedSettingValues.contains(currentSettingValue)) {
+ logInfo("Changing value for %s from %s to %s",
+ mSettingName, currentSettingValue, mSetValue);
device.executeShellCommand(shellCmdPut);
}
return;
@@ -102,6 +104,7 @@
/* Case 2: Only set-value given */
if (mSetValue != null) {
+ logInfo("Setting %s to value %s", mSettingName, mSetValue);
device.executeShellCommand(shellCmdPut);
return;
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
index 0100969..5863bd8 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
@@ -15,13 +15,11 @@
*/
package com.android.compatibility.common.tradefed.targetprep;
-import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -65,16 +63,15 @@
if (mWifiSsid == null) { // no connection to create, check for existing connectivity
if (!device.checkConnectivity()) {
throw new TargetSetupError("Device has no network connection, no ssid provided");
- }
+ }
} else { // network provided in options, attempt to create new connection
- CLog.logAndDisplay(LogLevel.INFO, "Attempting connection to \"%s\"", mWifiSsid);
- if (device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { // attempt connection
- CLog.logAndDisplay(LogLevel.INFO, "Connection successful");
- } else {
+ logInfo("Attempting connection to \"%s\"", mWifiSsid);
+ if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { // attempt connection
throw new TargetSetupError(String.format(
"Unable to connect to network \"%s\", some modules of CTS" +
"require an active network connection", mWifiSsid));
}
}
+ logInfo("Wifi is connected");
}
}
diff --git a/common/util/src/com/android/compatibility/common/util/ReportLog.java b/common/util/src/com/android/compatibility/common/util/ReportLog.java
index 445bbd4..37c39ef 100644
--- a/common/util/src/com/android/compatibility/common/util/ReportLog.java
+++ b/common/util/src/com/android/compatibility/common/util/ReportLog.java
@@ -46,19 +46,22 @@
private static final String SOURCE_ATTR = "source";
private static final String SUMMARY_TAG = "Summary";
private static final String VALUE_TAG = "Value";
+ private static final String DEFAULT_NAME = "default";
- private Metric mSummary;
- private final List<Metric> mDetails = new ArrayList<>();
+ protected Metric mSummary;
+ protected String mReportLogName;
+ protected String mStreamName;
+ protected final List<Metric> mDetails = new ArrayList<>();
public static class Metric implements Serializable {
private static final int MAX_SOURCE_LENGTH = 200;
private static final int MAX_MESSAGE_LENGTH = 200;
private static final int MAX_NUM_VALUES = 1000;
- private String mSource;
- private String mMessage;
- private double[] mValues;
- private ResultType mType;
- private ResultUnit mUnit;
+ String mSource;
+ String mMessage;
+ double[] mValues;
+ ResultType mType;
+ ResultUnit mUnit;
Metric(String source, String message, double value, ResultType type, ResultUnit unit) {
this(source, message, new double[] { value }, type, unit);
@@ -161,6 +164,15 @@
}
}
+ public ReportLog() {
+ mReportLogName = DEFAULT_NAME;
+ }
+
+ public ReportLog(String reportLogName, String streamName) {
+ mReportLogName = reportLogName;
+ mStreamName = streamName;
+ }
+
/**
* @param elem
*/
@@ -225,10 +237,12 @@
* NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
*/
public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
- setSummary(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(),
- message, value, type, unit));
+ setSummary(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(), message, value,
+ type, unit));
}
+ // TODO(mishragaurav): Add support for values of other types.
+
public Metric getSummary() {
return mSummary;
}
@@ -328,5 +342,4 @@
}
return report;
}
-
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index 25ee645..d81abb6 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -17,51 +17,23 @@
package android.appsecurity.cts;
import com.android.cts.migration.MigrationHelper;
-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
* {@link android.provider.DocumentsContract} and related intents.
*/
-public class DocumentsTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+public class DocumentsTest extends DocumentsTestCase {
private static final String PROVIDER_PKG = "com.android.cts.documentprovider";
private static final String PROVIDER_APK = "CtsDocumentProvider.apk";
- private static final String CLIENT_PKG = "com.android.cts.documentclient";
- private static final String CLIENT_APK = "CtsDocumentClient.apk";
-
- 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(PROVIDER_PKG);
- getDevice().uninstallPackage(CLIENT_PKG);
assertNull(getDevice().installPackage(
MigrationHelper.getTestFile(mCtsBuild, PROVIDER_APK), false));
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
}
@Override
@@ -69,7 +41,6 @@
super.tearDown();
getDevice().uninstallPackage(PROVIDER_PKG);
- getDevice().uninstallPackage(CLIENT_PKG);
}
public void testOpenSimple() throws Exception {
@@ -92,33 +63,6 @@
runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTree");
}
- public void testOpenExternalDirectory_invalidPath() throws Exception {
- runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenExternalDirectory_invalidPath");
- }
-
- public void testOpenExternalDirectory_userRejects() throws Exception {
- runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenExternalDirectory_userRejects");
- }
-
- public void testOpenExternalDirectory_userAccepts() throws Exception {
- runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenExternalDirectory_userAccepts");
- }
-
- public void testOpenExternalDirectory_notAskedAgain() throws Exception {
- runDeviceTests(CLIENT_PKG, ".DocumentsClientTest",
- "testOpenExternalDirectory_notAskedAgain");
- }
-
- public void testOpenExternalDirectory_userAcceptsNewDirectory() throws Exception {
- // TODO: figure out a better way to remove the directory.
- final String command = "rm -rf /sdcard/Pictures";
- final String output = getDevice().executeShellCommand(command);
- if (!output.trim().isEmpty()) {
- fail("Command '" + command + "' failed: '" + output + "'");
- }
- runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenExternalDirectory_userAccepts");
- }
-
public void testGetContent() throws Exception {
runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testGetContent");
}
@@ -126,9 +70,4 @@
public void testTransferDocument() throws Exception {
runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTransferDocument");
}
-
- public void runDeviceTests(String packageName, String testClassName, String testMethodName)
- throws DeviceNotAvailableException {
- Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
- }
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
new file mode 100644
index 0000000..7bd42b5
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -0,0 +1,71 @@
+/*
+ * 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 com.android.cts.migration.MigrationHelper;
+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;
+
+/**
+ * Base class for {@link android.provider.DocumentsContract} and related test cases.
+ */
+abstract class DocumentsTestCase extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+ protected static final String CLIENT_PKG = "com.android.cts.documentclient";
+ protected static final String CLIENT_APK = "CtsDocumentClient.apk";
+
+ protected IAbi mAbi;
+ protected 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(CLIENT_PKG);
+
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ getDevice().uninstallPackage(CLIENT_PKG);
+ }
+
+ public void runDeviceTests(String packageName, String testClassName, String testMethodName)
+ throws DeviceNotAvailableException {
+ Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ScopedDirectoryAccessTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ScopedDirectoryAccessTest.java
new file mode 100644
index 0000000..ffc7597
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ScopedDirectoryAccessTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+/**
+ * Set of tests that verify behavior of the Scoped Directory access API.
+ */
+public class ScopedDirectoryAccessTest extends DocumentsTestCase {
+
+ public void testInvalidPath() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest", "testInvalidPath");
+ }
+
+ public void testUserRejects() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest", "testUserRejects");
+ }
+
+ public void testUserAccepts() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest", "testUserAccepts");
+ }
+
+ public void testUserAcceptsNewDirectory() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest",
+ "testUserAcceptsNewDirectory");
+ }
+
+ public void testNotAskedAgain() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest", "testNotAskedAgain");
+ }
+
+ public void testDeniesOnceButAllowsAskingAgain() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest",
+ "testDeniesOnceButAllowsAskingAgain");
+ }
+
+ public void testDeniesOnceForAll() throws Exception {
+ runDeviceTests(CLIENT_PKG, ".ScopedDirectoryAccessClientTest", "testDeniesOnceForAll");
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
index ba27114..e7565d4 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
@@ -17,7 +17,6 @@
package com.android.cts.appaccessdata;
import java.io.BufferedReader;
-import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -26,6 +25,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.test.AndroidTestCase;
/**
@@ -85,32 +85,27 @@
*/
public void testAccessPublicData() throws IOException {
try {
- getOtherAppUid();
- } catch (FileNotFoundException e) {
- fail("Was not able to access another app's public file: " + e);
- } catch (SecurityException e) {
- fail("Was not able to access another app's public file: " + e);
+ // construct the absolute file path to the other app's public file
+ ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
+ File publicFile = new File(applicationInfo.dataDir, "files/" + PUBLIC_FILE_NAME);
+ FileInputStream inputStream = new FileInputStream(publicFile);
+ inputStream.read();
+ inputStream.close();
+ fail("Was able to access another app's public file");
+ } catch (FileNotFoundException | SecurityException e) {
+ // expected
}
}
- private int getOtherAppUid() throws IOException, FileNotFoundException, SecurityException {
- // construct the absolute file path to the other app's public file
- ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
- File publicFile = new File(applicationInfo.dataDir, "files/" + PUBLIC_FILE_NAME);
- DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFile));
- int otherAppUid = inputStream.readInt();
- inputStream.close();
- return otherAppUid;
- }
-
private void accessPrivateTrafficStats() throws IOException {
int otherAppUid = -1;
try {
- otherAppUid = getOtherAppUid();
- } catch (FileNotFoundException | SecurityException e) {
- fail("Was not able to access another app's public file: " + e);
+ otherAppUid = getContext()
+ .createPackageContext(APP_WITH_DATA_PKG, 0 /*flags*/)
+ .getApplicationInfo().uid;
+ } catch (NameNotFoundException e) {
+ fail("Was not able to find other app");
}
-
boolean foundOtherStats = false;
try {
BufferedReader qtaguidReader = new BufferedReader(new FileReader("/proc/net/xt_qtaguid/stats"));
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
index 378ef42..f3787e8 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
@@ -79,8 +79,7 @@
outputStream.close();
assertTrue(getContext().getFileStreamPath(PRIVATE_FILE_NAME).exists());
- outputStream = getContext().openFileOutput(PUBLIC_FILE_NAME,
- Context.MODE_WORLD_READABLE);
+ outputStream = getContext().openFileOutput(PUBLIC_FILE_NAME, 0 /*mode*/);
DataOutputStream dataOut = new DataOutputStream(outputStream);
dataOut.writeInt(getContext().getApplicationInfo().uid);
dataOut.close();
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 69583a7..acba1f4 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -16,58 +16,20 @@
package com.android.cts.documentclient;
-import static android.os.Environment.DIRECTORY_ALARMS;
-import static android.os.Environment.DIRECTORY_DCIM;
-import static android.os.Environment.DIRECTORY_DOCUMENTS;
-import static android.os.Environment.DIRECTORY_DOWNLOADS;
-import static android.os.Environment.DIRECTORY_MOVIES;
-import static android.os.Environment.DIRECTORY_MUSIC;
-import static android.os.Environment.DIRECTORY_NOTIFICATIONS;
-import static android.os.Environment.DIRECTORY_PICTURES;
-import static android.os.Environment.DIRECTORY_PODCASTS;
-import static android.os.Environment.DIRECTORY_RINGTONES;
-import static android.os.Environment.getExternalStorageDirectory;
-import static android.test.MoreAsserts.assertContainsRegex;
-import static android.test.MoreAsserts.assertNotEqual;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.Instrumentation;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.AssetFileDescriptor.AutoCloseInputStream;
-import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Environment;
import android.os.SystemClock;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsProvider;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Configurator;
-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;
-import android.test.InstrumentationTestCase;
import android.test.MoreAsserts;
-import android.text.format.DateUtils;
import android.util.Log;
-import android.view.MotionEvent;
import com.android.cts.documentclient.MyActivity.Result;
@@ -75,47 +37,9 @@
* Tests for {@link DocumentsProvider} and interaction with platform intents
* like {@link Intent#ACTION_OPEN_DOCUMENT}.
*/
-public class DocumentsClientTest extends InstrumentationTestCase {
+public class DocumentsClientTest extends DocumentsClientTestCase {
private static final String TAG = "DocumentsClientTest";
- private UiDevice mDevice;
- private MyActivity mActivity;
-
- private static final long TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS;
-
- private static final int REQUEST_CODE = 42;
-
- private static final String[] STANDARD_DIRECTORIES = {
- DIRECTORY_MUSIC,
- DIRECTORY_PODCASTS,
- DIRECTORY_RINGTONES,
- DIRECTORY_ALARMS,
- DIRECTORY_NOTIFICATIONS,
- DIRECTORY_PICTURES,
- DIRECTORY_MOVIES,
- DIRECTORY_DOWNLOADS,
- DIRECTORY_DCIM,
- DIRECTORY_DOCUMENTS
- };
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
-
- mDevice = UiDevice.getInstance(getInstrumentation());
- mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
- MyActivity.class, null);
- mDevice.waitForIdle();
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- mActivity.finish();
- }
-
private UiObject findRoot(String label) throws UiObjectNotFoundException {
final UiSelector rootsList = new UiSelector().resourceId(
"com.android.documentsui:id/container_roots").childSelector(
@@ -370,116 +294,6 @@
}
}
- public void testOpenExternalDirectory_invalidPath() throws Exception {
- if (!supportedHardware()) return;
-
- for (StorageVolume volume : getVolumes()) {
- openExternalDirectoryInvalidPath(volume, "");
- openExternalDirectoryInvalidPath(volume, "/dev/null");
- openExternalDirectoryInvalidPath(volume, "/../");
- openExternalDirectoryInvalidPath(volume, "/HiddenStuff");
- }
- }
-
- public void testOpenExternalDirectory_userRejects() throws Exception {
- if (!supportedHardware()) return;
-
- final String externalRoot = getExternalStorageDirectory().getPath();
-
- final StorageVolume primaryVolume = getPrimaryVolume();
-
- // Tests user clicking DENY button, for all valid directories.
- for (String directory : STANDARD_DIRECTORIES) {
- final Uri uri = Uri.fromFile(new File(externalRoot, directory));
-
- final UiAlertDialog dialog = openExternalDirectoryValidPath(primaryVolume, directory);
- dialog.noButton.click();
- assertActivityFailed();
- }
-
- // Also test user clicking back button - one directory is enough.
- openExternalDirectoryValidPath(primaryVolume, DIRECTORY_PICTURES);
- mDevice.pressBack();
- assertActivityFailed();
- }
-
- public void testOpenExternalDirectory_userAccepts() throws Exception {
- if (!supportedHardware())
- return;
-
- for (StorageVolume volume : getVolumes()) {
- userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_PICTURES);
- }
- }
-
- public void testOpenExternalDirectory_notAskedAgain() throws Exception {
- if (!supportedHardware())
- return;
-
- final StorageVolume volume = getPrimaryVolume();
- final Uri grantedUri = userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_PICTURES);
-
- // Calls it again - since the permission has been granted, it should return right away,
- // without popping up the permissions dialog.
- sendOpenExternalDirectoryIntent(volume, DIRECTORY_PICTURES);
- final Intent newData = assertActivitySucceeded();
- assertEquals(grantedUri, newData.getData());
-
- // Make sure other directories still require user permission.
- final Uri grantedUri2 = userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_ALARMS);
- assertNotEqual(grantedUri, grantedUri2);
- }
-
- private Uri userAcceptsOpenExternalDirectoryTest(StorageVolume volume, String directoryName)
- throws Exception {
- // Asserts dialog contain the proper message.
- final UiAlertDialog dialog = openExternalDirectoryValidPath(volume, directoryName);
- final String message = dialog.messageText.getText();
- Log.v(TAG, "request permission message: " + message);
- final Context context = getInstrumentation().getTargetContext();
- final String appLabel = context.getPackageManager().getApplicationLabel(
- context.getApplicationInfo()).toString();
- assertContainsRegex("missing app label", appLabel, message);
- assertContainsRegex("missing folder", directoryName, message);
- assertContainsRegex("missing root", volume.getDescription(context), message);
-
- // Call API...
- dialog.yesButton.click();
-
- // ...and get its response.
- final Intent data = assertActivitySucceeded();
- final Uri grantedUri = data.getData();
-
- // Test granted permission directly by persisting it...
- final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
- final int modeFlags = data.getFlags()
- & (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- resolver.takePersistableUriPermission(grantedUri, modeFlags);
-
- // ...and indirectly by creating some documents
- final Uri doc = DocumentsContract.buildDocumentUriUsingTree(grantedUri,
- DocumentsContract.getTreeDocumentId(grantedUri));
- assertNotNull("could not get tree URI", doc);
- final Uri pic = DocumentsContract.createDocument(resolver, doc, "image/png", "pic.png");
- assertNotNull("could not create file (pic.png) on tree root", pic);
- final Uri dir = DocumentsContract.createDocument(resolver, doc, Document.MIME_TYPE_DIR,
- "my dir");
- assertNotNull("could not create child dir (my dir)", pic);
- final Uri dirPic = DocumentsContract.createDocument(resolver, dir, "image/png", "pic2.png");
- assertNotNull("could not create file (pic.png) on child dir (my dir)", dirPic);
-
- writeFully(pic, "pic".getBytes());
- writeFully(dirPic, "dirPic".getBytes());
-
- // Clean up created documents.
- assertTrue("delete", DocumentsContract.deleteDocument(resolver, pic));
- assertTrue("delete", DocumentsContract.deleteDocument(resolver, dirPic));
- assertTrue("delete", DocumentsContract.deleteDocument(resolver, dir));
-
- return grantedUri;
- }
-
public void testGetContent() throws Exception {
if (!supportedHardware()) return;
@@ -614,126 +428,4 @@
cursorDst.close();
}
}
-
- private String getColumn(Uri uri, String column) {
- final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
- final Cursor cursor = resolver.query(uri, new String[] { column }, null, null, null);
- try {
- assertTrue(cursor.moveToFirst());
- return cursor.getString(0);
- } finally {
- cursor.close();
- }
- }
-
- private byte[] readFully(Uri uri) throws IOException {
- final InputStream in = getInstrumentation().getContext().getContentResolver()
- .openInputStream(uri);
- return readFully(in);
- }
-
- private byte[] readTypedFully(Uri uri, String mimeType) throws IOException {
- final AssetFileDescriptor descriptor =
- getInstrumentation().getContext().getContentResolver()
- .openTypedAssetFileDescriptor(uri, mimeType, null, null);
- try (AutoCloseInputStream in = new AutoCloseInputStream(descriptor)) {
- return readFully(in);
- }
- }
-
- private byte[] readFully(InputStream in) throws IOException {
- try {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int count;
- while ((count = in.read(buffer)) != -1) {
- bytes.write(buffer, 0, count);
- }
- return bytes.toByteArray();
- } finally {
- in.close();
- }
- }
-
- private void writeFully(Uri uri, byte[] data) throws IOException {
- OutputStream out = getInstrumentation().getContext().getContentResolver()
- .openOutputStream(uri);
- try {
- out.write(data);
- } finally {
- out.close();
- }
- }
-
- private boolean supportedHardware() {
- final PackageManager pm = getInstrumentation().getContext().getPackageManager();
- if (pm.hasSystemFeature("android.hardware.type.television")
- || pm.hasSystemFeature("android.hardware.type.watch")) {
- return false;
- }
- return true;
- }
-
- private void assertActivityFailed() {
- final Result result = mActivity.getResult();
- assertEquals(REQUEST_CODE, result.requestCode);
- assertEquals(Activity.RESULT_CANCELED, result.resultCode);
- assertNull(result.data);
- }
-
- private Intent assertActivitySucceeded() {
- final Result result = mActivity.getResult();
- assertEquals(REQUEST_CODE, result.requestCode);
- assertEquals(Activity.RESULT_OK, result.resultCode);
- assertNotNull(result.data);
- return result.data;
- }
-
- private void openExternalDirectoryInvalidPath(StorageVolume volume, String path) {
- sendOpenExternalDirectoryIntent(volume, path);
- assertActivityFailed();
- }
-
- private UiAlertDialog openExternalDirectoryValidPath(StorageVolume volume, String path)
- throws UiObjectNotFoundException {
- sendOpenExternalDirectoryIntent(volume, path);
- return new UiAlertDialog();
- }
-
- private void sendOpenExternalDirectoryIntent(StorageVolume volume, String directoryName) {
- final Intent intent = volume.createAccessIntent(directoryName);
- mActivity.startActivityForResult(intent, REQUEST_CODE);
- mDevice.waitForIdle();
- }
-
- private StorageVolume[] getVolumes() {
- final StorageManager sm = (StorageManager)
- getInstrumentation().getTargetContext().getSystemService(Context.STORAGE_SERVICE);
- final StorageVolume[] volumes = sm.getVolumeList();
- assertTrue("empty volumes", volumes.length > 0);
- return volumes;
- }
-
- private StorageVolume getPrimaryVolume() {
- final StorageManager sm = (StorageManager)
- getInstrumentation().getTargetContext().getSystemService(Context.STORAGE_SERVICE);
- return sm.getPrimaryVolume();
- }
-
- private final class UiAlertDialog {
- final UiObject messageText;
- final UiObject yesButton;
- final UiObject noButton;
-
- UiAlertDialog() throws UiObjectNotFoundException {
- final String id = "android:id/parentPanel";
- boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), TIMEOUT);
- assertTrue("object with id '(" + id + "') not visible yet", gotIt);
- final UiObject dialog = mDevice.findObject(new UiSelector().resourceId(id));
- assertTrue("object with id '(" + id + "') doesn't exist", dialog.exists());
- messageText = dialog.getChild(new UiSelector().resourceId("android:id/message"));
- yesButton = dialog.getChild(new UiSelector().resourceId("android:id/button1"));
- noButton = dialog.getChild(new UiSelector().resourceId("android:id/button2"));
- }
- }
}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
new file mode 100644
index 0000000..cb7dc48
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
@@ -0,0 +1,156 @@
+/*
+ * 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.documentclient;
+
+import static android.cts.util.SystemUtil.runShellCommand;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.android.cts.documentclient.MyActivity.Result;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetFileDescriptor.AutoCloseInputStream;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.MotionEvent;
+
+/**
+ * Base class for DocumentsUI test cases.
+ */
+abstract class DocumentsClientTestCase extends InstrumentationTestCase {
+ private static final String TAG = "DocumentsClientTestCase";
+
+ protected UiDevice mDevice;
+ protected MyActivity mActivity;
+
+ protected static final long TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS;
+ protected static final int REQUEST_CODE = 42;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+ MyActivity.class, null);
+ mDevice.waitForIdle();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ mActivity.finish();
+ }
+
+ protected String getColumn(Uri uri, String column) {
+ final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
+ final Cursor cursor = resolver.query(uri, new String[] { column }, null, null, null);
+ try {
+ assertTrue(cursor.moveToFirst());
+ return cursor.getString(0);
+ } finally {
+ cursor.close();
+ }
+ }
+
+ protected byte[] readFully(Uri uri) throws IOException {
+ final InputStream in = getInstrumentation().getContext().getContentResolver()
+ .openInputStream(uri);
+ return readFully(in);
+ }
+
+ protected byte[] readTypedFully(Uri uri, String mimeType) throws IOException {
+ final AssetFileDescriptor descriptor =
+ getInstrumentation().getContext().getContentResolver()
+ .openTypedAssetFileDescriptor(uri, mimeType, null, null);
+ try (AutoCloseInputStream in = new AutoCloseInputStream(descriptor)) {
+ return readFully(in);
+ }
+ }
+
+ protected byte[] readFully(InputStream in) throws IOException {
+ try {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytes.write(buffer, 0, count);
+ }
+ return bytes.toByteArray();
+ } finally {
+ in.close();
+ }
+ }
+
+ protected void writeFully(Uri uri, byte[] data) throws IOException {
+ OutputStream out = getInstrumentation().getContext().getContentResolver()
+ .openOutputStream(uri);
+ try {
+ out.write(data);
+ } finally {
+ out.close();
+ }
+ }
+
+ protected boolean supportedHardware() {
+ final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ if (pm.hasSystemFeature("android.hardware.type.television")
+ || pm.hasSystemFeature("android.hardware.type.watch")) {
+ return false;
+ }
+ return true;
+ }
+
+ protected void assertActivityFailed() {
+ final Result result = mActivity.getResult();
+ assertEquals(REQUEST_CODE, result.requestCode);
+ assertEquals(Activity.RESULT_CANCELED, result.resultCode);
+ assertNull(result.data);
+ }
+
+ protected Intent assertActivitySucceeded() {
+ final Result result = mActivity.getResult();
+ assertEquals(REQUEST_CODE, result.requestCode);
+ assertEquals(Activity.RESULT_OK, result.resultCode);
+ assertNotNull(result.data);
+ return result.data;
+ }
+
+ protected String executeShellCommand(String command) throws Exception {
+ final String result = runShellCommand(getInstrumentation(), command).trim();
+ Log.d(TAG, "Command '" + command + "' returned '" + result + "'");
+ return result;
+ }
+
+ protected void clearDocumentsUi() throws Exception {
+ executeShellCommand("pm clear com.android.documentsui");
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
new file mode 100644
index 0000000..3553bbf
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
@@ -0,0 +1,307 @@
+/*
+ * 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.documentclient;
+
+import static android.os.Environment.DIRECTORY_ALARMS;
+import static android.os.Environment.DIRECTORY_DCIM;
+import static android.os.Environment.DIRECTORY_DOCUMENTS;
+import static android.os.Environment.DIRECTORY_DOWNLOADS;
+import static android.os.Environment.DIRECTORY_MOVIES;
+import static android.os.Environment.DIRECTORY_MUSIC;
+import static android.os.Environment.DIRECTORY_NOTIFICATIONS;
+import static android.os.Environment.DIRECTORY_PICTURES;
+import static android.os.Environment.DIRECTORY_PODCASTS;
+import static android.os.Environment.DIRECTORY_RINGTONES;
+import static android.test.MoreAsserts.assertContainsRegex;
+import static android.test.MoreAsserts.assertNotEqual;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.util.Log;
+
+/**
+ * Set of tests that verify behavior of the Scoped Directory Access API.
+ */
+public class ScopedDirectoryAccessClientTest extends DocumentsClientTestCase {
+ private static final String TAG = "ScopedDirectoryAccessClientTest";
+
+ private static final String[] STANDARD_DIRECTORIES = {
+ DIRECTORY_MUSIC,
+ DIRECTORY_PODCASTS,
+ DIRECTORY_RINGTONES,
+ DIRECTORY_ALARMS,
+ DIRECTORY_NOTIFICATIONS,
+ DIRECTORY_PICTURES,
+ DIRECTORY_MOVIES,
+ DIRECTORY_DOWNLOADS,
+ DIRECTORY_DCIM,
+ DIRECTORY_DOCUMENTS
+ };
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // DocumentsUI caches some info like whether a user rejects a request, so we need to clear
+ // its data before each test.
+ clearDocumentsUi();
+ }
+
+ public void testInvalidPath() throws Exception {
+ if (!supportedHardware()) return;
+
+ for (StorageVolume volume : getVolumes()) {
+ openExternalDirectoryInvalidPath(volume, "");
+ openExternalDirectoryInvalidPath(volume, "/dev/null");
+ openExternalDirectoryInvalidPath(volume, "/../");
+ openExternalDirectoryInvalidPath(volume, "/HiddenStuff");
+ }
+ }
+
+ public void testUserRejects() throws Exception {
+ if (!supportedHardware()) return;
+
+ final StorageVolume primaryVolume = getPrimaryVolume();
+
+ // Tests user clicking DENY button, for all valid directories.
+ for (String directory : STANDARD_DIRECTORIES) {
+ final UiAlertDialog dialog = openExternalDirectoryValidPath(primaryVolume, directory);
+ dialog.noButton.click();
+ assertActivityFailed();
+ }
+
+ // Also test user clicking back button - one directory is enough.
+ openExternalDirectoryValidPath(primaryVolume, DIRECTORY_PICTURES);
+ mDevice.pressBack();
+ assertActivityFailed();
+ }
+
+ public void testUserAccepts() throws Exception {
+ if (!supportedHardware()) return;
+
+ for (StorageVolume volume : getVolumes()) {
+ userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_PICTURES);
+ }
+ }
+
+ public void testUserAcceptsNewDirectory() throws Exception {
+ if (!supportedHardware()) return;
+
+ // TODO: figure out a better way to remove the directory.
+ final String command = "rm -rf /sdcard/" + DIRECTORY_PICTURES;
+ final String output = executeShellCommand(command);
+ if (!output.isEmpty()) {
+ fail("Command '" + command + "' failed: '" + output + "'");
+ }
+ userAcceptsOpenExternalDirectoryTest(getPrimaryVolume(), DIRECTORY_PICTURES);
+ }
+
+ public void testNotAskedAgain() throws Exception {
+ if (!supportedHardware()) return;
+
+ final StorageVolume volume = getPrimaryVolume();
+ final Uri grantedUri = userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_PICTURES);
+
+ // Calls it again - since the permission has been granted, it should return right away,
+ // without popping up the permissions dialog.
+ sendOpenExternalDirectoryIntent(volume, DIRECTORY_PICTURES);
+ final Intent newData = assertActivitySucceeded();
+ assertEquals(grantedUri, newData.getData());
+
+ // Make sure other directories still require user permission.
+ final Uri grantedUri2 = userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_ALARMS);
+ assertNotEqual(grantedUri, grantedUri2);
+ }
+
+ public void testDeniesOnceButAllowsAskingAgain() throws Exception {
+ if (!supportedHardware())return;
+
+ for (StorageVolume volume : getVolumes()) {
+ // Rejects the first attempt...
+ UiAlertDialog dialog = openExternalDirectoryValidPath(volume, DIRECTORY_DCIM);
+ dialog.assertDoNotAskAgainVisibility(false);
+ dialog.noButton.click();
+ assertActivityFailed();
+
+ // ...and the second.
+ dialog = openExternalDirectoryValidPath(volume, DIRECTORY_DCIM);
+ dialog.assertDoNotAskAgainVisibility(true);
+ dialog.noButton.click();
+ assertActivityFailed();
+
+ // Third time is a charm...
+ userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_DCIM);
+ }
+ }
+
+ public void testDeniesOnceForAll() throws Exception {
+ if (!supportedHardware()) return;
+
+ for (StorageVolume volume : getVolumes()) {
+ // Rejects the first attempt...
+ UiAlertDialog dialog = openExternalDirectoryValidPath(volume, DIRECTORY_RINGTONES);
+ dialog.assertDoNotAskAgainVisibility(false);
+ dialog.noButton.click();
+ assertActivityFailed();
+
+ // ...and the second, checking the box
+ dialog = openExternalDirectoryValidPath(volume, DIRECTORY_RINGTONES);
+ UiObject checkbox = dialog.assertDoNotAskAgainVisibility(true);
+ assertTrue("checkbox should not be checkable", checkbox.isCheckable());
+ assertFalse("checkbox should not be checked", checkbox.isChecked());
+ checkbox.click();
+ assertTrue("checkbox should be checked", checkbox.isChecked()); // Sanity check
+ assertFalse("allow button should be disabled", dialog.yesButton.isEnabled());
+
+ dialog.noButton.click();
+ assertActivityFailed();
+
+ // Third strike out...
+ sendOpenExternalDirectoryIntent(volume, DIRECTORY_RINGTONES);
+ assertActivityFailed();
+ }
+ }
+
+ private Uri userAcceptsOpenExternalDirectoryTest(StorageVolume volume, String directoryName)
+ throws Exception {
+ // Asserts dialog contain the proper message.
+ final UiAlertDialog dialog = openExternalDirectoryValidPath(volume, directoryName);
+ final String message = dialog.messageText.getText();
+ Log.v(TAG, "request permission message: " + message);
+ final Context context = getInstrumentation().getTargetContext();
+ final String appLabel = context.getPackageManager().getApplicationLabel(
+ context.getApplicationInfo()).toString();
+ assertContainsRegex("missing app label", appLabel, message);
+ assertContainsRegex("missing folder", directoryName, message);
+ assertContainsRegex("missing root", volume.getDescription(context), message);
+
+ // Call API...
+ dialog.yesButton.click();
+
+ // ...and get its response.
+ final Intent data = assertActivitySucceeded();
+ final Uri grantedUri = data.getData();
+
+ // Test granted permission directly by persisting it...
+ final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
+ final int modeFlags = data.getFlags()
+ & (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ resolver.takePersistableUriPermission(grantedUri, modeFlags);
+
+ // ...and indirectly by creating some documents
+ final Uri doc = DocumentsContract.buildDocumentUriUsingTree(grantedUri,
+ DocumentsContract.getTreeDocumentId(grantedUri));
+ assertNotNull("could not get tree URI", doc);
+ final Uri pic = DocumentsContract.createDocument(resolver, doc, "image/png", "pic.png");
+ assertNotNull("could not create file (pic.png) on tree root", pic);
+ final Uri dir = DocumentsContract.createDocument(resolver, doc, Document.MIME_TYPE_DIR,
+ "my dir");
+ assertNotNull("could not create child dir (my dir)", pic);
+ final Uri dirPic = DocumentsContract.createDocument(resolver, dir, "image/png", "pic2.png");
+ assertNotNull("could not create file (pic.png) on child dir (my dir)", dirPic);
+
+ writeFully(pic, "pic".getBytes());
+ writeFully(dirPic, "dirPic".getBytes());
+
+ // Clean up created documents.
+ assertTrue("delete", DocumentsContract.deleteDocument(resolver, pic));
+ assertTrue("delete", DocumentsContract.deleteDocument(resolver, dirPic));
+ assertTrue("delete", DocumentsContract.deleteDocument(resolver, dir));
+
+ return grantedUri;
+ }
+
+ private void openExternalDirectoryInvalidPath(StorageVolume volume, String path) {
+ sendOpenExternalDirectoryIntent(volume, path);
+ assertActivityFailed();
+ }
+
+ private UiAlertDialog openExternalDirectoryValidPath(StorageVolume volume, String path)
+ throws UiObjectNotFoundException {
+ sendOpenExternalDirectoryIntent(volume, path);
+ return new UiAlertDialog();
+ }
+
+ private void sendOpenExternalDirectoryIntent(StorageVolume volume, String directoryName) {
+ final Intent intent = volume.createAccessIntent(directoryName);
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+ mDevice.waitForIdle();
+ }
+
+ private StorageVolume[] getVolumes() {
+ final StorageManager sm = (StorageManager)
+ getInstrumentation().getTargetContext().getSystemService(Context.STORAGE_SERVICE);
+ final StorageVolume[] volumes = sm.getVolumeList();
+ assertTrue("empty volumes", volumes.length > 0);
+ return volumes;
+ }
+
+ private StorageVolume getPrimaryVolume() {
+ final StorageManager sm = (StorageManager)
+ getInstrumentation().getTargetContext().getSystemService(Context.STORAGE_SERVICE);
+ return sm.getPrimaryVolume();
+ }
+
+ private final class UiAlertDialog {
+ final UiObject dialog;
+ final UiObject messageText;
+ final UiObject yesButton;
+ final UiObject noButton;
+
+ UiAlertDialog() throws UiObjectNotFoundException {
+ final String id = "android:id/parentPanel";
+ boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), TIMEOUT);
+ assertTrue("object with id '(" + id + "') not visible yet", gotIt);
+ dialog = mDevice.findObject(new UiSelector().resourceId(id));
+ assertTrue("object with id '(" + id + "') doesn't exist", dialog.exists());
+ messageText = dialog.getChild(
+ new UiSelector().resourceId("com.android.documentsui:id/message"));
+ yesButton = dialog.getChild(new UiSelector().resourceId("android:id/button1"));
+ noButton = dialog.getChild(new UiSelector().resourceId("android:id/button2"));
+ }
+
+ private UiObject getDoNotAskAgainCheckBox() throws UiObjectNotFoundException {
+ return dialog.getChild(
+ new UiSelector().resourceId("com.android.documentsui:id/do_not_ask_checkbox"));
+ }
+
+ UiObject assertDoNotAskAgainVisibility(boolean expectVisible) {
+ UiObject checkbox = null;
+ try {
+ checkbox = getDoNotAskAgainCheckBox();
+ assertEquals("Wrong value for 'DoNotAskAgain.exists()",
+ expectVisible, checkbox.exists());
+ } catch (UiObjectNotFoundException e) {
+ if (expectVisible) {
+ fail("'Do Not Ask Again' not found");
+ }
+ }
+ return checkbox;
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
index 824e285..b42414c 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
@@ -32,20 +32,20 @@
android:exported="true" />
<activity android:name=".AwareActivity"
- android:encryptionAware="true"
+ android:directBootAware="true"
android:exported="true" />
<receiver android:name=".AwareReceiver"
- android:encryptionAware="true"
+ android:directBootAware="true"
android:exported="true" />
<service android:name=".AwareService"
- android:encryptionAware="true"
+ android:directBootAware="true"
android:exported="true" />
<provider android:name=".AwareProvider"
android:authorities="com.android.cts.encryptionapp.aware"
- android:encryptionAware="true"
+ android:directBootAware="true"
android:exported="true" />
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/AndroidManifest.xml
index c51444d..8b15f1f 100644
--- a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/AndroidManifest.xml
@@ -20,5 +20,6 @@
A simple app used to test that instrumentation cannot target an app signed with a different
certificate.
-->
+ <application />
</manifest>
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
index 923fc44..9ecc339 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.UserManager;
@@ -183,13 +184,13 @@
}
}
- public void testSetApplicationRestrictionsManagingPackage() {
+ public void testSetApplicationRestrictionsManagingPackage() throws NameNotFoundException {
final String previousValue = mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
ADMIN_RECEIVER_COMPONENT);
try {
mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE);
- assertEquals(OTHER_PACKAGE,
+ ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG);
+ assertEquals(APP_RESTRICTIONS_TARGET_PKG,
mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
ADMIN_RECEIVER_COMPONENT));
mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
@@ -205,6 +206,22 @@
}
}
+ public void testSetApplicationRestrictionsManagingPackageForNotInstalledPackage()
+ throws NameNotFoundException {
+ try {
+ mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
+ OTHER_PACKAGE);
+ fail("Not throwing exception for not installed package name");
+ } catch (NameNotFoundException expected) {
+ MoreAsserts.assertContainsRegex(OTHER_PACKAGE, expected.getMessage());
+ } finally {
+ mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
+ null);
+ assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
+ ADMIN_RECEIVER_COMPONENT));
+ }
+ }
+
// Should be consistent with assertBundle0
private static Bundle createBundle0() {
Bundle result = new Bundle();
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java
index 890daa3..aaa017b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java
@@ -19,6 +19,7 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Process;
import android.util.Log;
@@ -94,8 +95,12 @@
+ " for user " + Process.myUserHandle());
} else if (COMMAND_SET_APP_RESTRICTIONS_MANAGER.equals(command)) {
String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
- dpm.setApplicationRestrictionsManagingPackage(
- BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, packageName);
+ try {
+ dpm.setApplicationRestrictionsManagingPackage(
+ BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, packageName);
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
Log.i(TAG, "Setting the application restrictions managing package to " + packageName);
} else {
Log.e(TAG, "Invalid command: " + command);
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index 91663c7..391ef15 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -16,6 +16,7 @@
package com.android.cts.deviceowner;
+import android.app.ActivityManager;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -46,6 +47,7 @@
private static final int BROADCAST_TIMEOUT = 15_000;
private static final int USER_SWITCH_DELAY = 10_000;
private PackageManager mPackageManager;
+ private ActivityManager mActivityManager;
private volatile boolean mReceived;
private volatile boolean mTestProfileOwnerWasUsed;
private volatile boolean mSetupComplete;
@@ -55,6 +57,7 @@
protected void setUp() throws Exception {
super.setUp();
mPackageManager = mContext.getPackageManager();
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
@Override
@@ -241,7 +244,11 @@
}
public void testCreateAndManageUser_DontSkipSetupWizard() {
- createAndManageUserTest(0);
+ if (!mActivityManager.isRunningInTestHarness()) {
+ // In test harness, the setup wizard will be disabled by default, so this test is always
+ // failing.
+ createAndManageUserTest(0);
+ }
}
// createAndManageUser should circumvent the DISALLOW_ADD_USER restriction
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceLoggingTest.java
deleted file mode 100644
index 642915f..0000000
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceLoggingTest.java
+++ /dev/null
@@ -1,76 +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 com.android.cts.deviceowner;
-
-import android.auditing.SecurityLog.SecurityEvent;
-import android.os.UserHandle;
-
-import java.util.List;
-
-public class DeviceLoggingTest extends BaseDeviceOwnerTest {
-
- private static final String MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED =
- "There should only be one user, managed by Device Owner";
-
- /**
- * Test: setting device logging can only be done if there's one user on the device.
- */
- public void testSetDeviceLoggingEnabledNotPossibleIfMoreThanOneUserPresent() {
- try {
- mDevicePolicyManager.setDeviceLoggingEnabled(getWho(), true);
- fail("did not throw expected SecurityException");
- } catch (SecurityException e) {
- assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
- }
- }
-
- /**
- * Test: retrieving device logs can only be done if there's one user on the device.
- */
- public void testRetrievingDeviceLogsNotPossibleIfMoreThanOneUserPresent() {
- try {
- mDevicePolicyManager.retrieveDeviceLogs(getWho());
- fail("did not throw expected SecurityException");
- } catch (SecurityException e) {
- assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
- }
- }
-
- /**
- * Test: retrieving previous device logs can only be done if there's one user on the device.
- */
- public void testRetrievingPreviousDeviceLogsNotPossibleIfMoreThanOneUserPresent() {
- try {
- mDevicePolicyManager.retrievePreviousDeviceLogs(getWho());
- fail("did not throw expected SecurityException");
- } catch (SecurityException e) {
- assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
- }
- }
-
- /**
- * Test: retrieving device logs should be rate limited - subsequent attempts should return null.
- * TODO(mkarpinski): consider how we can test that the rate limiting is set to 2 hours.
- */
- public void testRetrievingDeviceLogsNotPossibleImmediatelyAfterPreviousSuccessfulRetrieval() {
- List<SecurityEvent> logs = mDevicePolicyManager.retrieveDeviceLogs(getWho());
- // if logs is null it means that that attempt was rate limited => test PASS
- if (logs != null) {
- assertNull(mDevicePolicyManager.retrieveDeviceLogs(getWho()));
- assertNull(mDevicePolicyManager.retrieveDeviceLogs(getWho()));
- }
- }
-}
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
new file mode 100644
index 0000000..f61c796
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.deviceowner;
+
+import android.content.Context;
+import android.os.CpuUsageInfo;
+import android.os.HardwarePropertiesManager;
+import android.os.SystemClock;
+
+import java.lang.Math;
+
+/**
+ * Test {@link HardwarePropertiesManager}
+ */
+public class HardwarePropertiesManagerTest extends BaseDeviceOwnerTest {
+ public static final int MAX_FAN_SPEED = 20000;
+ public static final int MAX_DEVICE_TEMPERATURE = 200;
+ public static final int MONITORING_ITERATION_NUMBER = 10;
+
+ // Time between checks in milliseconds.
+ public static final long SLEEP_TIME = 10;
+
+ private void checkFanSpeed(float speed) {
+ assertTrue(speed >= 0 && speed < MAX_FAN_SPEED);
+ }
+
+ private void checkDeviceTemp(float temp, float throttlingTemp, float shutdownTemp) {
+ // Check validity of current temperature.
+ assertTrue(Math.abs(temp) < MAX_DEVICE_TEMPERATURE
+ || temp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
+
+ // Compare current temperature and shutdown threshold.
+ assertTrue(temp < shutdownTemp
+ || shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
+ // Compare throttling and shutdown thresholds.
+ assertTrue(throttlingTemp < shutdownTemp
+ || throttlingTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE
+ || shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
+ }
+
+ private void checkCpuUsageInfo(CpuUsageInfo info) {
+ assertTrue(info == null || (info.getActive() >= 0 && info.getTotal() >= 0
+ && info.getTotal() >= info.getActive()));
+ }
+
+ private void checkFanSpeeds(float[] fanSpeeds) {
+ for (float speed : fanSpeeds) {
+ checkFanSpeed(speed);
+ }
+ }
+
+ private void checkTemps(float[] temps, float[] throttlingThresholds,
+ float[] shutdownThresholds) {
+ assertEquals(temps.length, throttlingThresholds.length);
+ assertEquals(temps.length, shutdownThresholds.length);
+ for (int i = 0; i < temps.length; ++i) {
+ checkDeviceTemp(temps[i], throttlingThresholds[i], shutdownThresholds[i]);
+ }
+ }
+
+ private void checkCpuUsages(CpuUsageInfo[] cpuUsages) {
+ for (CpuUsageInfo info : cpuUsages) {
+ checkCpuUsageInfo(info);
+ }
+ }
+
+ // Check validity of new array of fan speeds:
+ // the number of fans should be the same.
+ private void checkFanSpeeds(float[] speeds, float[] oldSpeeds) {
+ assertEquals(speeds.length, oldSpeeds.length);
+ }
+
+ // Check validity of new array of cpu usages:
+ // The number of CPUs should be the same and total/active time should not decrease.
+ private void checkCpuUsages(CpuUsageInfo[] infos,
+ CpuUsageInfo[] oldInfos) {
+ assertEquals(infos.length, oldInfos.length);
+ for (int i = 0; i < infos.length; ++i) {
+ assertTrue(oldInfos[i] == null || infos[i] == null
+ || (oldInfos[i].getActive() <= infos[i].getActive()
+ && oldInfos[i].getTotal() <= infos[i].getTotal()));
+ }
+ }
+
+ /**
+ * test points:
+ * 1. Get fan speeds, device temperatures and CPU usage information.
+ * 2. Check for validity.
+ * 3. Sleep.
+ * 4. Do it 10 times and compare with old ones.
+ */
+ public void testHardwarePropertiesManager() throws InterruptedException,
+ SecurityException {
+ HardwarePropertiesManager hm = (HardwarePropertiesManager) getContext().getSystemService(
+ Context.HARDWARE_PROPERTIES_SERVICE);
+
+ float[] oldFanSpeeds = hm.getFanSpeeds();
+
+ float[] cpuTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ float[] cpuThrottlingThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ float[] cpuShutdownThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+ HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+ float[] gpuTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ float[] gpuThrottlingThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ float[] gpuShutdownThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+ HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+ float[] batteryTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ float[] batteryThrottlingThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ float[] batteryShutdownThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+ HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+ float[] skinTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ float[] skinThrottlingThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ float[] skinShutdownThresholds = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+ CpuUsageInfo[] oldCpuUsages = hm.getCpuUsages();
+
+ checkFanSpeeds(oldFanSpeeds);
+ checkTemps(cpuTemps, cpuThrottlingThresholds, cpuShutdownThresholds);
+ checkTemps(gpuTemps, gpuThrottlingThresholds, gpuShutdownThresholds);
+ checkTemps(batteryTemps, batteryThrottlingThresholds, batteryShutdownThresholds);
+ checkTemps(skinTemps, skinThrottlingThresholds, skinShutdownThresholds);
+ checkCpuUsages(oldCpuUsages);
+
+ for (int i = 0; i < MONITORING_ITERATION_NUMBER; i++) {
+ Thread.sleep(SLEEP_TIME);
+
+ float[] fanSpeeds = hm.getFanSpeeds();
+ cpuTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ gpuTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ batteryTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ skinTemps = hm.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ CpuUsageInfo[] cpuUsages = hm.getCpuUsages();
+
+ checkFanSpeeds(fanSpeeds);
+ checkTemps(cpuTemps, cpuThrottlingThresholds, cpuShutdownThresholds);
+ checkTemps(gpuTemps, gpuThrottlingThresholds, gpuShutdownThresholds);
+ checkTemps(batteryTemps, batteryThrottlingThresholds, batteryShutdownThresholds);
+ checkTemps(skinTemps, skinThrottlingThresholds, skinShutdownThresholds);
+ checkCpuUsages(cpuUsages);
+
+ // No need to compare length of old and new temperature arrays:
+ // they are compared through throttling and shutdown threshold arrays lengths.
+ checkFanSpeeds(fanSpeeds, oldFanSpeeds);
+ checkCpuUsages(cpuUsages, oldCpuUsages);
+
+ oldFanSpeeds = fanSpeeds;
+ oldCpuUsages = cpuUsages;
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java
new file mode 100644
index 0000000..c70ed16
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.deviceowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+/**
+ * The following test can run in DeviceOwner mode or non-DeviceOwner mode.
+ * Don't inherit {@link BaseDeviceOwnerTest}
+ */
+public class PreDeviceOwnerTest extends AndroidTestCase {
+
+ protected DevicePolicyManager mDevicePolicyManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mDevicePolicyManager = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ }
+
+ public void testIsProvisioningAllowedFalse() {
+ assertFalse(mDevicePolicyManager.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE));
+ }
+
+ public void testIsProvisioningAllowedFalseForManagedProfileAction() {
+ assertFalse(mDevicePolicyManager
+ .isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE));
+ }
+
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SecurityLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SecurityLoggingTest.java
new file mode 100644
index 0000000..0c1f421
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SecurityLoggingTest.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 com.android.cts.deviceowner;
+
+import android.app.admin.SecurityLog.SecurityEvent;
+import android.os.UserHandle;
+
+import java.util.List;
+
+public class SecurityLoggingTest extends BaseDeviceOwnerTest {
+
+ private static final String MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED =
+ "There should only be one user, managed by Device Owner";
+
+ /**
+ * Test: setting security logging can only be done if there's one user on the device.
+ */
+ public void testSetSecurityLoggingEnabledNotPossibleIfMoreThanOneUserPresent() {
+ try {
+ mDevicePolicyManager.setSecurityLoggingEnabled(getWho(), true);
+ fail("did not throw expected SecurityException");
+ } catch (SecurityException e) {
+ assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
+ }
+ }
+
+ /**
+ * Test: retrieving security logs can only be done if there's one user on the device.
+ */
+ public void testRetrievingSecurityLogsNotPossibleIfMoreThanOneUserPresent() {
+ try {
+ mDevicePolicyManager.retrieveSecurityLogs(getWho());
+ fail("did not throw expected SecurityException");
+ } catch (SecurityException e) {
+ assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
+ }
+ }
+
+ /**
+ * Test: retrieving previous security logs can only be done if there's one user on the device.
+ */
+ public void testRetrievingPreviousSecurityLogsNotPossibleIfMoreThanOneUserPresent() {
+ try {
+ mDevicePolicyManager.retrievePreRebootSecurityLogs(getWho());
+ fail("did not throw expected SecurityException");
+ } catch (SecurityException e) {
+ assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
+ }
+ }
+
+ /**
+ * Test: retrieving security logs should be rate limited - subsequent attempts should return
+ * null.
+ */
+ public void testRetrievingSecurityLogsNotPossibleImmediatelyAfterPreviousSuccessfulRetrieval() {
+ List<SecurityEvent> logs = mDevicePolicyManager.retrieveSecurityLogs(getWho());
+ // if logs is null it means that that attempt was rate limited => test PASS
+ if (logs != null) {
+ assertNull(mDevicePolicyManager.retrieveSecurityLogs(getWho()));
+ assertNull(mDevicePolicyManager.retrieveSecurityLogs(getWho()));
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PreManagedProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PreManagedProfileTest.java
new file mode 100644
index 0000000..99fd50d
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PreManagedProfileTest.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 com.android.cts.managedprofile;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+public class PreManagedProfileTest extends AndroidTestCase {
+
+ protected DevicePolicyManager mDevicePolicyManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mDevicePolicyManager = (DevicePolicyManager) mContext
+ .getSystemService(Context.DEVICE_POLICY_SERVICE);
+ }
+
+ public void testIsProvisioningAllowedTrue() {
+ assertTrue(mDevicePolicyManager
+ .isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE));
+ }
+
+ public void testIsProvisioningAllowedFalse() {
+ assertFalse(mDevicePolicyManager
+ .isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE));
+ }
+
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
index 96affae..1bb797f 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
@@ -33,11 +33,11 @@
private static final BySelector POPUP_BUTTON_SELECTOR = By
.clazz(android.widget.Button.class.getName())
.res("android:id/button1")
- .pkg("com.google.android.packageinstaller");
- private static final BySelector POPUP_TEXT_SELECTOR = By
- .clazz(android.widget.TextView.class.getName())
- .res("android:id/alertTitle")
- .pkg("com.google.android.packageinstaller");
+ .pkg("com.android.settings");
+ private static final BySelector POPUP_IMAGE_SELECTOR = By
+ .clazz(android.widget.ImageView.class.getName())
+ .res("com.android.settings:id/admin_support_icon")
+ .pkg("com.android.settings");
private static final BySelector INSTALL_BUTTON_SELECTOR = By
.clazz(android.widget.Button.class.getName())
.res("com.android.packageinstaller:id/ok_button")
@@ -106,9 +106,9 @@
}
private void automateDismissInstallBlockedDialog() {
- mDevice.wait(Until.hasObject(POPUP_TEXT_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
- UiObject2 text = mDevice.findObject(POPUP_TEXT_SELECTOR);
- assertNotNull("Alert dialog not found", text);
+ mDevice.wait(Until.hasObject(POPUP_IMAGE_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+ UiObject2 icon = mDevice.findObject(POPUP_IMAGE_SELECTOR);
+ assertNotNull("Policy transparency dialog icon not found", icon);
// "OK" button only present in the dialog if it is blocked by policy.
UiObject2 button = mDevice.findObject(POPUP_BUTTON_SELECTOR);
assertNotNull("OK button not found", button);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 60bbc55..3919dc3 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -61,6 +61,13 @@
protected static final int FLAG_GUEST = 0x00000004;
protected static final int FLAG_EPHEMERAL = 0x00000100;
+ protected static interface Settings {
+ public static final String GLOBAL_NAMESPACE = "global";
+ public static interface Global {
+ public static final String DEVICE_PROVISIONED = "device_provisioned";
+ }
+ }
+
protected IBuildInfo mCtsBuild;
private String mPackageVerifier;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 61ae4f3..23cdb5a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,6 +16,7 @@
package com.android.cts.devicepolicy;
+import com.android.cts.devicepolicy.BaseDevicePolicyTest.Settings;
import com.android.cts.migration.MigrationHelper;
import java.io.File;
@@ -149,4 +150,18 @@
getDevice().uninstallPackage(PACKAGE_INSTALLER_PKG);
}
}
+
+ public void testIsProvisioningAllowed() throws Exception {
+ // Must install the apk since the test runs in the DO apk.
+ installAppAsUser(DEVICE_OWNER_APK, mPrimaryUserId);
+ try {
+ // When CTS runs, setupwizard is complete. Expects it has to return false as DO can
+ // only be provisioned before setupwizard is completed.
+
+ assertTrue(runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".PreDeviceOwnerTest",
+ "testIsProvisioningAllowedFalse", /* deviceOwnerUserId */ 0));
+ } finally {
+ getDevice().uninstallPackage(DEVICE_OWNER_PKG);
+ }
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java
new file mode 100644
index 0000000..53e9138
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.devicepolicy;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+public class CustomManagedProfileTest extends BaseDevicePolicyTest {
+
+ private static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
+ private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // We need multi user to be supported in order to create a profile of the user owner.
+ mHasFeature = mHasFeature && hasDeviceFeature("android.software.managed_users");
+ }
+
+ public void testIsProvisioningAllowed() throws Exception {
+ final int primaryUserId = getPrimaryUser();
+ // Must install the apk since the test runs in the ManagedProfile apk.
+ installAppAsUser(MANAGED_PROFILE_APK, mPrimaryUserId);
+ try {
+ if (mHasFeature) {
+ // Since we assume, in ManagedProfileTest, provisioning has to be successful,
+ // DevicePolicyManager.isProvisioningAllowed must return true
+ assertIsProvisioningAllowed(true, primaryUserId);
+ } else {
+ // Test the case when feature flag is off
+ assertIsProvisioningAllowed(false, primaryUserId);
+ }
+ } finally {
+ getDevice().uninstallPackage(MANAGED_PROFILE_PKG);
+ }
+ }
+
+ private void assertIsProvisioningAllowed(boolean expected, int userId)
+ throws DeviceNotAvailableException {
+ final String testName = expected ? "testIsProvisioningAllowedTrue"
+ : "testIsProvisioningAllowedFalse";
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest", testName,
+ userId));
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 6a22a5c..18ed0a6 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -291,27 +291,27 @@
}
}
- public void testDeviceLoggingWithTwoUsers() throws Exception {
+ public void testSecurityLoggingWithTwoUsers() throws Exception {
if (!mHasFeature || getMaxNumberOfUsersSupported() < 2) {
return;
}
int userId = -1;
try {
userId = createUser();
- executeDeviceTestMethod(".DeviceLoggingTest",
- "testSetDeviceLoggingEnabledNotPossibleIfMoreThanOneUserPresent");
- executeDeviceTestMethod(".DeviceLoggingTest",
- "testRetrievingDeviceLogsNotPossibleIfMoreThanOneUserPresent");
- executeDeviceTestMethod(".DeviceLoggingTest",
- "testRetrievingPreviousDeviceLogsNotPossibleIfMoreThanOneUserPresent");
+ executeDeviceTestMethod(".SecurityLoggingTest",
+ "testSetSecurityLoggingEnabledNotPossibleIfMoreThanOneUserPresent");
+ executeDeviceTestMethod(".SecurityLoggingTest",
+ "testRetrievingSecurityLogsNotPossibleIfMoreThanOneUserPresent");
+ executeDeviceTestMethod(".SecurityLoggingTest",
+ "testRetrievingPreviousSecurityLogsNotPossibleIfMoreThanOneUserPresent");
} finally {
removeUser(userId);
}
}
- public void testDeviceLoggingWithSingleUser() throws Exception {
- executeDeviceTestMethod(".DeviceLoggingTest",
- "testRetrievingDeviceLogsNotPossibleImmediatelyAfterPreviousSuccessfulRetrieval");
+ public void testSecurityLoggingWithSingleUser() throws Exception {
+ executeDeviceTestMethod(".SecurityLoggingTest",
+ "testRetrievingSecurityLogsNotPossibleImmediatelyAfterPreviousSuccessfulRetrieval");
}
public void testLockTask() throws Exception {
@@ -357,6 +357,26 @@
}
}
+ // Execute HardwarePropertiesManagerTest as a device owner.
+ public void testHardwarePropertiesManagerAsDeviceOwner() throws Exception {
+ if (!mHasFeature)
+ return;
+
+ executeDeviceTestMethod(".HardwarePropertiesManagerTest", "testHardwarePropertiesManager");
+ }
+
+ public void testIsManagedDeviceProvisioningAllowed() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ // This case runs when DO is provisioned
+ // mHasFeature == true and provisioned, can't provision DO again.
+ executeDeviceTestMethod(".PreDeviceOwnerTest", "testIsProvisioningAllowedFalse");
+ // Can't provision Managed Profile when DO is on
+ executeDeviceTestMethod(".PreDeviceOwnerTest",
+ "testIsProvisioningAllowedFalseForManagedProfileAction");
+ }
+
private void executeDeviceOwnerTest(String testClassName) throws Exception {
if (!mHasFeature) {
return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 13fd921..8eaa606 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -591,6 +591,20 @@
}
}
+ public void testIsProvisioningAllowed() throws DeviceNotAvailableException {
+ if (!mHasFeature) {
+ return;
+ }
+ // In Managed profile user when managed profile is provisioned
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest",
+ "testIsProvisioningAllowedFalse", mProfileUserId));
+
+ // In parent user when managed profile is provisioned
+ // It's allowed to provision again by removing the previous profile
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest",
+ "testIsProvisioningAllowedTrue", mParentUserId));
+ }
+
private void setDirectoryPrefix(String directoryName, int userId)
throws DeviceNotAvailableException {
String command = "content call --uri " + DIRECTORY_PRIVOIDER_URI
diff --git a/hostsidetests/net/AndroidTest.xml b/hostsidetests/net/AndroidTest.xml
index 4b6994a..9945805 100644
--- a/hostsidetests/net/AndroidTest.xml
+++ b/hostsidetests/net/AndroidTest.xml
@@ -16,5 +16,6 @@
<configuration description="Config for CTS net host test cases">
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsHostsideNetworkTests.jar" />
+ <option name="runtime-hint" value="3m56s" />
</test>
</configuration>
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 def3439..adaaf84 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
@@ -221,7 +221,7 @@
if (result.equals(expectedResult))
return;
Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
- + expectedResult + "' on attempt #; sleeping 1s before polling again");
+ + expectedResult + "' on attempt #" + i + "; sleeping 1s before trying again");
Thread.sleep(SECOND_IN_MS);
}
fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
@@ -253,13 +253,12 @@
Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered);
final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered;
- final String result = executeShellCommand(setCommand);
- assertTrue("Command '" + setCommand + "' failed: " + result, result.isEmpty());
+ assertDelayedShellCommand(setCommand, "");
// Sanity check.
- final String newStatus = executeShellCommand("cmd netpolicy get metered-network " + netId);
- assertEquals("Metered status of wi-fi network " + netId + " not set properly",
- newStatus.trim(), Boolean.toString(metered));
+ final String getCommand = "cmd netpolicy get metered-network " + netId;
+ assertDelayedShellCommand(getCommand, Boolean.toString(metered));
+
return netId;
}
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 59b73f4..a18b82d 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -602,11 +602,6 @@
assertDomainZeroOrOne("u:r:drmserver:s0", "/system/bin/drmserver");
}
- /* Media server is always running */
- public void testMediaserverDomain() throws DeviceNotAvailableException {
- assertDomainN("u:r:mediaserver:s0", "media.log", "/system/bin/mediaserver");
- }
-
/* Installd is always running */
public void testInstalldDomain() throws DeviceNotAvailableException {
assertDomainOne("u:r:installd:s0", "/system/bin/installd");
diff --git a/hostsidetests/services/activitymanager/AndroidTest.xml b/hostsidetests/services/activitymanager/AndroidTest.xml
index ce407a3..641fa09 100644
--- a/hostsidetests/services/activitymanager/AndroidTest.xml
+++ b/hostsidetests/services/activitymanager/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsServicesHostTestCases.jar" />
+ <option name="runtime-hint" value="4m7s" />
</test>
</configuration>
diff --git a/hostsidetests/services/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
index 8a2a448..39fb19f 100755
--- a/hostsidetests/services/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
@@ -24,6 +24,10 @@
android:resizeableActivity="true"
android:exported="true"
/>
+ <activity android:name=".NonResizeableActivity"
+ android:resizeableActivity="false"
+ android:exported="true"
+ />
<activity android:name=".DockedActivity"
android:resizeableActivity="true"
android:exported="true"
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
new file mode 100644
index 0000000..6312b47
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.server.app;
+
+public class NonResizeableActivity extends AbstractLifecycleLogActivity {
+
+ private static final String TAG = NonResizeableActivity.class.getSimpleName();
+
+ @Override
+ protected String getTag() {
+ return TAG;
+ }
+}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
index e74ecdf..63e1dbe 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -61,6 +61,9 @@
retry = false;
}
} while (retry && retriesLeft-- > 0);
+
+ assertSanity();
+ assertValidBounds();
}
private boolean shouldRetry(String[] waitForActivitiesVisible) {
@@ -114,7 +117,7 @@
assertTrue(msg, mWmState.containsStack(stackId));
}
- void assertDoesNotContainsStack(String msg, int stackId) throws Exception {
+ void assertDoesNotContainStack(String msg, int stackId) throws Exception {
assertFalse(msg, mAmState.containsStack(stackId));
assertFalse(msg, mWmState.containsStack(stackId));
}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
index e077f7e..877e53b 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
@@ -32,7 +32,6 @@
mDevice.executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
mAmWmState.computeState(mDevice, new String[] {VISIBLE_BEHIND_ACTIVITY});
- mAmWmState.assertSanity();
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertFrontStack("Home stack must be the front stack.", HOME_STACK_ID);
@@ -46,7 +45,6 @@
mAmWmState.computeState(mDevice,
new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertSanity();
mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
}
@@ -57,7 +55,6 @@
mAmWmState.computeState(mDevice,
new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertSanity();
mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
}
@@ -73,7 +70,6 @@
mDevice.executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
mAmWmState.computeState(mDevice, new String[] {PIP_ON_PIP_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertSanity();
mAmWmState.assertFrontStack("Pinned stack must be the front stack.", PINNED_STACK_ID);
mAmWmState.assertVisibility(PIP_ON_PIP_ACTIVITY, true);
mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index 840fb7f..58a7ae6 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -17,12 +17,14 @@
package android.server.cts;
import java.awt.Rectangle;
+import java.util.ArrayList;
import static com.android.ddmlib.Log.LogLevel.*;
public class ActivityManagerDockedStackTests extends ActivityManagerTestBase {
private static final String TEST_ACTIVITY_NAME = "TestActivity";
+ private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity";
private static final String DOCKED_ACTIVITY_NAME = "DockedActivity";
private static final String LAUNCH_TO_SIDE_ACTIVITY_NAME = "LaunchToSideActivity";
private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
@@ -30,31 +32,38 @@
private static final int TASK_SIZE = 600;
private static final int STACK_SIZE = 300;
- // TODO: Add test for non-resizeable activity.
-
public void testStackList() throws Exception {
mDevice.executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
- mAmWmState.assertSanity();
mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID);
}
public void testDockActivity() throws Exception {
launchActivityInDockStack(TEST_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
- mAmWmState.assertSanity();
mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
}
+ public void testNonResizeableNotDocked() throws Exception {
+ launchActivityInDockStack(NON_RESIZEABLE_ACTIVITY_NAME);
+ mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME});
+
+ mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
+ mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID);
+ mAmWmState.assertFrontStack(
+ "Fullscreen stack must be front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+ }
+
public void testLaunchToSide() throws Exception {
launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME);
printStacksAndTasks();
launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {LAUNCH_TO_SIDE_ACTIVITY_NAME});
- mAmWmState.assertSanity();
+
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
@@ -65,41 +74,32 @@
launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME);
final String[] waitForActivitiesVisible = new String[] {LAUNCH_TO_SIDE_ACTIVITY_NAME};
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertSanity();
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
- // Rotate device single steps (90°) 0-1-2-3
+ // Rotate device single steps (90°) 0-1-2-3.
+ // Each time we compute the state we implicitly assert valid bounds.
setDeviceRotation(0);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(1);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(2);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(3);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
// Double steps (180°) We ended the single step at 3. So, we jump directly to 1 for double
// step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side.
setDeviceRotation(1);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(3);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(0);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(2);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
setDeviceRotation(0);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
}
public void testRotationWhenDockedWhileLocked() throws Exception {
@@ -116,25 +116,21 @@
setDeviceRotation(0);
unlockDevice();
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
lockDevice();
setDeviceRotation(1);
unlockDevice();
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
lockDevice();
setDeviceRotation(2);
unlockDevice();
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
lockDevice();
setDeviceRotation(3);
unlockDevice();
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- mAmWmState.assertValidBounds();
}
public void testResizeDockedStack() throws Exception {
@@ -142,7 +138,6 @@
launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME});
- mAmWmState.assertSanity();
mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
mAmWmState.assertContainsStack("Must contain fullscreen stack",
FULLSCREEN_WORKSPACE_STACK_ID);
@@ -164,7 +159,6 @@
mAmWmState.computeState(mDevice,
new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
- mAmWmState.assertSanity();
final Rectangle initialDockBounds =
mAmWmState.getWmState().getStack(DOCKED_STACK_ID).getBounds();
@@ -180,7 +174,6 @@
mAmWmState.computeState(mDevice,
new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
- mAmWmState.assertSanity();
assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
index 786e8e1..f86d9ec 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
@@ -17,6 +17,7 @@
package android.server.cts;
import java.awt.Rectangle;
+import java.util.ArrayList;
public class ActivityManagerFreeformStackTests extends ActivityManagerTestBase {
@@ -28,6 +29,7 @@
// NOTE: Launching the FreeformActivity will automatically launch the TestActivity
// with bounds (0, 0, 500, 500)
private static final String FREEFORM_ACTIVITY = "FreeformActivity";
+ private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
private static final String NO_RELAUNCH_ACTIVITY = "NoRelaunchActivity";
public void testFreeformWindowManagementSupport() throws Exception {
@@ -35,11 +37,9 @@
launchActivityInStack(FREEFORM_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
mAmWmState.computeState(mDevice, new String[] {FREEFORM_ACTIVITY});
- mAmWmState.assertSanity();
- mAmWmState.assertValidBounds();
if (!supportsFreeform()) {
- mAmWmState.assertDoesNotContainsStack(
+ mAmWmState.assertDoesNotContainStack(
"Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
return;
}
@@ -54,15 +54,25 @@
mAmWmState.getAmState().getTaskByActivityName(TEST_ACTIVITY).getBounds());
}
+ public void testNonResizeableActivityNotLaunchedToFreeform() throws Exception {
+ launchActivityInStack(NON_RESIZEABLE_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
+
+ mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY});
+
+ mAmWmState.assertFrontStack(
+ "Fullscreen stack must be the front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertDoesNotContainStack(
+ "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
+ }
+
public void testActivityLifeCycleOnResizeFreeformTask() throws Exception {
launchActivityInStack(TEST_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
launchActivityInStack(NO_RELAUNCH_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
- mAmWmState.assertSanity();
if (!supportsFreeform()) {
- mAmWmState.assertDoesNotContainsStack(
+ mAmWmState.assertDoesNotContainStack(
"Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
return;
}
@@ -73,7 +83,6 @@
TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_1, TEST_TASK_SIZE_2);
mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
- mAmWmState.assertSanity();
clearLogcat();
resizeActivityTask(TEST_ACTIVITY,
@@ -81,7 +90,6 @@
resizeActivityTask(NO_RELAUNCH_ACTIVITY,
TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
- mAmWmState.assertSanity();
assertActivityLifecycle(TEST_ACTIVITY, true);
assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
index bae3c6e..f0008eb 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
@@ -146,8 +146,6 @@
mAmWmState.computeState(mDevice, true /* visibleOnly */, new String[] {activityName});
- mAmWmState.assertSanity();
-
mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
mAmWmState.getWmState().getMatchingWindowState(windowName, mTempWindowList);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index 4250404..c57b648 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -52,8 +52,6 @@
}
mAmWmState.computeState(mDevice, new String[] {topActiviyName});
- mAmWmState.assertSanity();
- mAmWmState.assertValidBounds();
if (supportsPip()) {
final String windowName = getWindowName(topActiviyName);
@@ -81,7 +79,7 @@
"Pinned window can't be focused window.", windowName);
}
} else {
- mAmWmState.assertDoesNotContainsStack(
+ mAmWmState.assertDoesNotContainStack(
"Must not contain pinned stack.", PINNED_STACK_ID);
}
}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
index 298a759..624128b 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
@@ -86,8 +86,6 @@
throws Exception {
mAmWmState.computeState(mDevice, visibleOnly, new String[] {activityName});
- mAmWmState.assertSanity();
-
mAmWmState.assertFocusedWindow("Test window must be the front window.",
windowName);
diff --git a/hostsidetests/systemui/Android.mk b/hostsidetests/systemui/Android.mk
index 1c0dd06..41f05ef 100644
--- a/hostsidetests/systemui/Android.mk
+++ b/hostsidetests/systemui/Android.mk
@@ -28,6 +28,8 @@
LOCAL_CTS_TEST_PACKAGE := android.host.systemui
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
diff --git a/hostsidetests/systemui/OldAndroidTest.xml b/hostsidetests/systemui/OldAndroidTest.xml
new file mode 100644
index 0000000..2efcb94
--- /dev/null
+++ b/hostsidetests/systemui/OldAndroidTest.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.
+-->
+<configuration description="Config for CTS System UI host test cases">
+
+ <include name="common-config" />
+ <!-- This will tell tradefed to install the test apk. -->
+ <option name="cts-apk-installer:test-file-name" value="CtsSystemUiDeviceApp.apk" />
+</configuration>
diff --git a/hostsidetests/theme/AndroidTest.xml b/hostsidetests/theme/AndroidTest.xml
index 516df3d..50418ec 100644
--- a/hostsidetests/theme/AndroidTest.xml
+++ b/hostsidetests/theme/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsThemeHostTestCases.jar" />
+ <option name="runtime-hint" value="5h2m34s" />
</test>
</configuration>
diff --git a/suite/audio_quality/lib/src/audio/AudioLocal.cpp b/suite/audio_quality/lib/src/audio/AudioLocal.cpp
index 71b7afb..2a65689 100644
--- a/suite/audio_quality/lib/src/audio/AudioLocal.cpp
+++ b/suite/audio_quality/lib/src/audio/AudioLocal.cpp
@@ -23,7 +23,7 @@
// gain control not necessary in MobilePre as there is no control.
// This means audio source itself should be adjusted to control volume
if (mState == EStNone) {
- if (run() != android::NO_ERROR) {
+ if (run("AudioLocal") != android::NO_ERROR) {
LOGE("AudioLocal cannot run");
// cannot run thread
return false;
diff --git a/suite/audio_quality/lib/src/audio/RemoteAudio.cpp b/suite/audio_quality/lib/src/audio/RemoteAudio.cpp
index d9b7c51..ead04b91 100644
--- a/suite/audio_quality/lib/src/audio/RemoteAudio.cpp
+++ b/suite/audio_quality/lib/src/audio/RemoteAudio.cpp
@@ -59,7 +59,7 @@
bool RemoteAudio::init(int port)
{
mPort = port;
- if (run() != android::NO_ERROR) {
+ if (run("RemoteAudio") != android::NO_ERROR) {
LOGE("RemoteAudio cannot run");
// cannot run thread
return false;
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
index 40b67c8..62c7124 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
@@ -41,18 +41,6 @@
assertTrue("Timed out waiting for override deadline.", executed);
}
- public void testSchedulePeriodic() throws Exception {
- JobInfo periodicJob =
- new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
- .setPeriodic(5000L) // 5 second period.
- .build();
-
- kTestEnvironment.setExpectedExecutions(3);
- mJobScheduler.schedule(periodicJob);
- final boolean countedDown = kTestEnvironment.awaitExecution();
- assertTrue("Timed out waiting for periodic jobs to execute", countedDown);
- }
-
public void testCancel() throws Exception {
JobInfo cancelJob = new JobInfo.Builder(CANCEL_JOB_ID, kJobServiceComponent)
.setMinimumLatency(5000L) // make sure it doesn't actually run immediately
@@ -106,4 +94,4 @@
" JobParameters#isOverrideDeadlineExpired=false",
kTestEnvironment.getLastJobParameters().isOverrideDeadlineExpired());
}
-}
\ No newline at end of file
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index bc88085..bb199b4 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -24,6 +24,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
import java.util.List;
@@ -63,6 +64,19 @@
};
assertTrue(mAccessibilityManager.addAccessibilityStateChangeListener(listener));
assertTrue(mAccessibilityManager.removeAccessibilityStateChangeListener(listener));
+ assertFalse(mAccessibilityManager.removeAccessibilityStateChangeListener(listener));
+ }
+
+ public void testAddAndRemoveTouchExplorationStateChangeListener() throws Exception {
+ TouchExplorationStateChangeListener listener = new TouchExplorationStateChangeListener() {
+ @Override
+ public void onTouchExplorationStateChanged(boolean enabled) {
+ // Do nothing.
+ }
+ };
+ assertTrue(mAccessibilityManager.addTouchExplorationStateChangeListener(listener));
+ assertTrue(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
+ assertFalse(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
}
public void testIsTouchExplorationEnabled() throws Exception {
@@ -173,6 +187,10 @@
AccessibilityEvent.TYPE_VIEW_CLICKED));
}
+ public void testTouchExplorationStateChanged() throws Exception {
+ waitForTouchExplorationEnabled();
+ }
+
private void waitForAccessibilityEnabled() throws InterruptedException {
final Object waitObject = new Object();
@@ -192,6 +210,29 @@
}
}
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
- assertTrue("Time out enabling accessibility", mAccessibilityManager.isEnabled());
+ assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
+ }
+
+ private void waitForTouchExplorationEnabled() throws InterruptedException {
+ final Object waitObject = new Object();
+
+ TouchExplorationStateChangeListener listener = new TouchExplorationStateChangeListener() {
+ @Override
+ public void onTouchExplorationStateChanged(boolean b) {
+ synchronized (waitObject) {
+ waitObject.notifyAll();
+ }
+ }
+ };
+ mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
+ long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
+ synchronized (waitObject) {
+ if (!mAccessibilityManager.isEnabled() && (System.currentTimeMillis() < timeoutTime)) {
+ waitObject.wait(timeoutTime - System.currentTimeMillis());
+ }
+ }
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
+ assertTrue("Timed out enabling touch exploration",
+ mAccessibilityManager.isTouchExplorationEnabled());
}
}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
new file mode 100644
index 0000000..d64bd94
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.view.accessibility.cts;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
+
+/**
+ * Class for testing {@link CollectionInfo}.
+ */
+public class AccessibilityNodeInfo_CollectionInfoTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testObtain() {
+ CollectionInfo c;
+
+ c = CollectionInfo.obtain(0, 1, true);
+ assertNotNull(c);
+ assertEquals(0, c.getRowCount());
+ assertEquals(1, c.getColumnCount());
+ assertTrue(c.isHierarchical());
+ assertEquals(CollectionInfo.SELECTION_MODE_NONE, c.getSelectionMode());
+
+ c = CollectionInfo.obtain(1, 2, true, CollectionInfo.SELECTION_MODE_MULTIPLE);
+ assertNotNull(c);
+ assertEquals(1, c.getRowCount());
+ assertEquals(2, c.getColumnCount());
+ assertTrue(c.isHierarchical());
+ assertEquals(CollectionInfo.SELECTION_MODE_MULTIPLE, c.getSelectionMode());
+ }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
new file mode 100644
index 0000000..954d762
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.view.accessibility.cts;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.RangeInfo;
+
+/**
+ * Class for testing {@link AccessibilityNodeInfo.RangeInfo}.
+ */
+public class AccessibilityNodeInfo_RangeInfoTest extends AndroidTestCase {
+
+ /** Allowed tolerance for floating point equality comparisons. */
+ public static final float FLOAT_TOLERANCE = 0.001f;
+
+ @SmallTest
+ public void testObtain() {
+ RangeInfo r;
+
+ r = RangeInfo.obtain(RangeInfo.RANGE_TYPE_INT, -100, 0, -50);
+ assertEquals(RangeInfo.RANGE_TYPE_INT, r.getType());
+ assertEquals(-100, r.getMin(), FLOAT_TOLERANCE);
+ assertEquals(0, r.getMax(), FLOAT_TOLERANCE);
+ assertEquals(-50, r.getCurrent(), FLOAT_TOLERANCE);
+
+ r = RangeInfo.obtain(RangeInfo.RANGE_TYPE_FLOAT, -1.5f, 1.5f, 0.0f);
+ assertEquals(RangeInfo.RANGE_TYPE_FLOAT, r.getType());
+ assertEquals(-1.5f, r.getMin(), FLOAT_TOLERANCE);
+ assertEquals(1.5f, r.getMax(), FLOAT_TOLERANCE);
+ assertEquals(0.0f, r.getCurrent(), FLOAT_TOLERANCE);
+
+ r = RangeInfo.obtain(RangeInfo.RANGE_TYPE_PERCENT, 0.0f, 100.0f, 50.0f);
+ assertEquals(RangeInfo.RANGE_TYPE_PERCENT, r.getType());
+ assertEquals(0.0f, r.getMin(), FLOAT_TOLERANCE);
+ assertEquals(100.0f, r.getMax(), FLOAT_TOLERANCE);
+ assertEquals(50.0f, r.getCurrent(), FLOAT_TOLERANCE);
+ }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
new file mode 100644
index 0000000..eeee235
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.view.accessibility.cts;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.accessibility.AccessibilityNodeProvider;
+
+/**
+ * Class for testing {@link AccessibilityNodeProvider}.
+ */
+public class AccessibilityNodeProviderTest extends AndroidTestCase {
+ @SmallTest
+ public void testDefaultBehavior() {
+ AccessibilityNodeProvider p = new AccessibilityNodeProvider() {
+ // Class is abstract, but has no abstract methods.
+ };
+
+ assertNull(p.createAccessibilityNodeInfo(0));
+ assertNull(p.findAccessibilityNodeInfosByText(null, 0));
+ assertNull(p.findFocus(0));
+ assertFalse(p.performAction(0, 0, null));
+ }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
new file mode 100644
index 0000000..293feec
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.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 android.view.accessibility.cts;
+
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+/**
+ * Class for testing {@link AccessibilityWindowInfo}.
+ */
+public class AccessibilityWindowInfoTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testObtain() {
+ AccessibilityWindowInfo w1 = AccessibilityWindowInfo.obtain();
+ assertNotNull(w1);
+
+ AccessibilityWindowInfo w2 = AccessibilityWindowInfo.obtain(w1);
+ assertNotSame(w1, w2);
+ assertEquals(w1, w2);
+ }
+
+ @SmallTest
+ public void testParceling() {
+ Parcel parcel = Parcel.obtain();
+ AccessibilityWindowInfo w1 = AccessibilityWindowInfo.obtain();
+ w1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AccessibilityWindowInfo w2 = AccessibilityWindowInfo.CREATOR.createFromParcel(parcel);
+ assertNotSame(w1, w2);
+ assertEquals(w1, w2);
+
+ }
+
+ @SmallTest
+ public void testDefaultValues() {
+ AccessibilityWindowInfo w = AccessibilityWindowInfo.obtain();
+ assertEquals(0, w.getChildCount());
+ assertEquals(-1, w.getType());
+ assertEquals(-1, w.getLayer());
+ assertEquals(-1, w.getId());
+ assertEquals(0, w.describeContents());
+ assertNull(w.getParent());
+ assertNull(w.getRoot());
+ assertFalse(w.isAccessibilityFocused());
+ assertFalse(w.isActive());
+ assertFalse(w.isFocused());
+
+ Rect rect = new Rect();
+ w.getBoundsInScreen(rect);
+ assertTrue(rect.isEmpty());
+
+ try {
+ w.getChild(0);
+ fail("Expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected.
+ }
+ }
+
+ @SmallTest
+ public void testRecycle() {
+ AccessibilityWindowInfo w = AccessibilityWindowInfo.obtain();
+ w.recycle();
+
+ try {
+ w.recycle();
+ fail("Expected IllegalStateException");
+ } catch (IllegalStateException e) {
+ // Expected.
+ }
+ }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
index 34beb59..997ee61 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
@@ -67,7 +67,9 @@
putSecureSetting("accessibility_captioning_enabled", "1");
assertTrue("Observed enabled change", listener.wasEnabledChangedCalled);
+ // Style change gets posted in a Runnable, so we need to wait for idle.
putSecureSetting("accessibility_captioning_preset", "-1");
+ getInstrumentation().waitForIdleSync();
assertTrue("Observed user style change", listener.wasUserStyleChangedCalled);
putSecureSetting("accessibility_captioning_locale", "ja_JP");
diff --git a/tests/accessibility/src/android/view/accessibility/cts/SpeakingAccessibilityService.java b/tests/accessibility/src/android/view/accessibility/cts/SpeakingAccessibilityService.java
index afa08cd..219a2ff 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/SpeakingAccessibilityService.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/SpeakingAccessibilityService.java
@@ -17,6 +17,7 @@
package android.view.accessibility.cts;
import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -34,6 +35,10 @@
@Override
protected void onServiceConnected() {
+ final AccessibilityServiceInfo info = getServiceInfo();
+ info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+ setServiceInfo(info);
+
synchronized (sWaitObjectForConnecting) {
sConnectedInstance = this;
sWaitObjectForConnecting.notifyAll();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/VibratingAccessibilityService.java b/tests/accessibility/src/android/view/accessibility/cts/VibratingAccessibilityService.java
index 6bf522e..41edf9f 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/VibratingAccessibilityService.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/VibratingAccessibilityService.java
@@ -17,6 +17,7 @@
package android.view.accessibility.cts;
import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -34,6 +35,10 @@
@Override
protected void onServiceConnected() {
+ final AccessibilityServiceInfo info = getServiceInfo();
+ info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+ setServiceInfo(info);
+
synchronized (sWaitObjectForConnecting) {
sConnectedInstance = this;
sWaitObjectForConnecting.notifyAll();
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
index 1287524..fe261dc 100644
--- a/tests/accessibilityservice/AndroidTest.xml
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.accessibilityservice.cts" />
+ <option name="runtime-hint" value="2m12s" />
</test>
</configuration>
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 2a17486..52af854 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -17,16 +17,19 @@
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.GestureDescription;
+import android.accessibilityservice.GestureDescription.Builder;
+import android.accessibilityservice.GestureDescription.StrokeDescription;
import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Path;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -96,7 +99,7 @@
final int clickYInsideView = 20;
int clickX = clickXInsideView + mViewBounds.left;
int clickY = clickYInsideView + mViewBounds.top;
- GestureDescription click = GestureDescription.createClick(clickX, clickY);
+ GestureDescription click = createClick(clickX, clickY);
assertTrue(StubGestureAccessibilityService.sConnectedInstance
.doDispatchGesture(click, mCallback, null));
mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
@@ -144,7 +147,7 @@
final int clickYInsideView = 20;
int clickX = clickXInsideView + mViewBounds.left;
int clickY = clickYInsideView + mViewBounds.top;
- GestureDescription longClick = GestureDescription.createLongClick(clickX, clickY);
+ GestureDescription longClick = createLongClick(clickX, clickY);
assertTrue(StubGestureAccessibilityService.sConnectedInstance
.doDispatchGesture(longClick, mCallback, null));
mCallback.assertGestureCompletes(
@@ -186,8 +189,7 @@
int gestureTime = 500;
float swipeTolerance = 2.0f;
- GestureDescription swipe = GestureDescription
- .createSwipe(startX, startY, endX, endY, gestureTime);
+ GestureDescription swipe = createSwipe(startX, startY, endX, endY, gestureTime);
assertTrue(StubGestureAccessibilityService.sConnectedInstance
.doDispatchGesture(swipe, mCallback, null));
mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
@@ -231,8 +233,7 @@
int endY = endYInsideView + mViewBounds.top;
int gestureTime = 1000;
- GestureDescription swipe = GestureDescription
- .createSwipe(startX, startY, endX, endY, gestureTime);
+ GestureDescription swipe = createSwipe(startX, startY, endX, endY, gestureTime);
assertTrue(StubGestureAccessibilityService.sConnectedInstance
.doDispatchGesture(swipe, mCallback, null));
mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
@@ -269,7 +270,7 @@
int gestureTime = 500;
float pinchTolerance = 2.0f;
- GestureDescription pinch = GestureDescription.createPinch(centerX, centerY, startSpacing,
+ GestureDescription pinch = createPinch(centerX, centerY, startSpacing,
endSpacing, 45.0F, gestureTime);
assertTrue(StubGestureAccessibilityService.sConnectedInstance
.doDispatchGesture(pinch, mCallback, null));
@@ -481,4 +482,84 @@
}
}
}
+
+ private GestureDescription createClick(int x, int y) {
+ Path clickPath = new Path();
+ clickPath.moveTo(x, y);
+ clickPath.lineTo(x + 1, y);
+ GestureDescription.StrokeDescription clickStroke =
+ new GestureDescription.StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout());
+ GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
+ clickBuilder.addStroke(clickStroke);
+ return clickBuilder.build();
+ }
+
+ private GestureDescription createLongClick(int x, int y) {
+ Path clickPath = new Path();
+ clickPath.moveTo(x, y);
+ clickPath.lineTo(x + 1, y);
+ int longPressTime = ViewConfiguration.getLongPressTimeout();
+
+ GestureDescription.StrokeDescription longClickStroke =
+ new GestureDescription.StrokeDescription(clickPath, 0, longPressTime + (longPressTime / 2));
+ GestureDescription.Builder longClickBuilder = new GestureDescription.Builder();
+ longClickBuilder.addStroke(longClickStroke);
+ return longClickBuilder.build();
+ }
+
+ private GestureDescription createSwipe(
+ int startX, int startY, int endX, int endY, long duration) {
+ Path swipePath = new Path();
+ swipePath.moveTo(startX, startY);
+ swipePath.lineTo(endX, endY);
+
+ GestureDescription.StrokeDescription swipeStroke = new GestureDescription.StrokeDescription(swipePath, 0, duration);
+ GestureDescription.Builder swipeBuilder = new GestureDescription.Builder();
+ swipeBuilder.addStroke(swipeStroke);
+ return swipeBuilder.build();
+ }
+
+ private GestureDescription createPinch(int centerX, int centerY, int startSpacing,
+ int endSpacing, float orientation, long duration) {
+ if ((startSpacing < 0) || (endSpacing < 0)) {
+ throw new IllegalArgumentException("Pinch spacing cannot be negative");
+ }
+ float[] startPoint1 = new float[2];
+ float[] endPoint1 = new float[2];
+ float[] startPoint2 = new float[2];
+ float[] endPoint2 = new float[2];
+
+ /* Build points for a horizontal gesture centered at the origin */
+ startPoint1[0] = startSpacing / 2;
+ startPoint1[1] = 0;
+ endPoint1[0] = endSpacing / 2;
+ endPoint1[1] = 0;
+ startPoint2[0] = -startSpacing / 2;
+ startPoint2[1] = 0;
+ endPoint2[0] = -endSpacing / 2;
+ endPoint2[1] = 0;
+
+ /* Rotate and translate the points */
+ Matrix matrix = new Matrix();
+ matrix.setRotate(orientation);
+ matrix.postTranslate(centerX, centerY);
+ matrix.mapPoints(startPoint1);
+ matrix.mapPoints(endPoint1);
+ matrix.mapPoints(startPoint2);
+ matrix.mapPoints(endPoint2);
+
+ Path path1 = new Path();
+ path1.moveTo(startPoint1[0], startPoint1[1]);
+ path1.lineTo(endPoint1[0], endPoint1[1]);
+ Path path2 = new Path();
+ path2.moveTo(startPoint2[0], startPoint2[1]);
+ path2.lineTo(endPoint2[0], endPoint2[1]);
+
+ GestureDescription.StrokeDescription path1Stroke = new GestureDescription.StrokeDescription(path1, 0, duration);
+ GestureDescription.StrokeDescription path2Stroke = new GestureDescription.StrokeDescription(path2, 0, duration);
+ GestureDescription.Builder swipeBuilder = new GestureDescription.Builder();
+ swipeBuilder.addStroke(path1Stroke);
+ swipeBuilder.addStroke(path2Stroke);
+ return swipeBuilder.build();
+ }
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
index b696cba..b3fa9d2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
@@ -119,7 +119,7 @@
public void testAddStroke_allowUpToMaxPaths() {
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
- for (int i = 0; i < GestureDescription.MAX_STROKE_COUNT; i++) {
+ for (int i = 0; i < GestureDescription.getMaxStrokeCount(); i++) {
Path path = new Path();
path.moveTo(i, i);
path.lineTo(10 + i, 10 + i);
@@ -144,7 +144,7 @@
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
try {
gestureBuilder.addStroke(new GestureDescription.StrokeDescription(
- path, 0, GestureDescription.MAX_GESTURE_DURATION_MS + 1));
+ path, 0, GestureDescription.getMaxGestureDuration() + 1));
fail("Missing exception for adding stroke with duration too long.");
} catch (RuntimeException e) {
}
@@ -159,151 +159,6 @@
}
}
-
- public void testClickAt_negativeX_shouldThrow() {
- try {
- GestureDescription.createClick(-1, 0);
- fail("Missing exception for clicking at negative x coordinate.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testClickAt_negativeY_shouldThrow() {
- try {
- GestureDescription.createClick(0, -1);
- fail("Missing exception for clicking at negative y coordinate.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testLongClickAt_negativeX_shouldThrow() {
- try {
- GestureDescription.createLongClick(-1, 0);
- fail("Missing exception for long clicking at negative x coordinate.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testLongClickAt_negativeY_shouldThrow() {
- try {
- GestureDescription.createLongClick(0, -1);
- fail("Missing exception for long clicking at negative y coordinate.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testZeroDurationSwipe_shouldThrow() {
- try {
- GestureDescription.createSwipe(0, 0, 100, 100, 0);
- fail("Missing exception for creating zero duration swipe.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testNegativeDurationSwipe_shouldThrow() {
- try {
- GestureDescription.createSwipe(0, 0, 100, 100, -1);
- fail("Missing exception for creating negative duration swipe.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testZeroLengthSwipe_shouldThrow() {
- try {
- GestureDescription.createSwipe(0, 0, 0, 0, 10);
- fail("Missing exception for creating zero-length swipe.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testSwipe_negativeStartX_shouldThrow() {
- try {
- GestureDescription.createSwipe(-1, 0, 0, 0, 10);
- fail("Missing exception for creating swipe with negative starting x.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testSwipe_negativeStartY_shouldThrow() {
- try {
- GestureDescription.createSwipe(0, -1, 0, 0, 10);
- fail("Missing exception for creating swipe with negative starting y.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testSwipe_negativeEndX_shouldThrow() {
- try {
- GestureDescription.createSwipe(0, 0, -1, 0, 10);
- fail("Missing exception for creating swipe with negative ending x.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testSwipe_negativeEndY_shouldThrow() {
- try {
- GestureDescription.createSwipe(0, 0, 0, -1, 10);
- fail("Missing exception for creating swipe with negative ending y.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testZeroDurationPinch_shouldBeNull() {
- try {
- GestureDescription.createPinch(100, 100, 50, 75, 0, 0);
- fail("Missing exception for creating pinch with zero duration.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testNegativeDurationPinch_shouldBeNull() {
- try {
- GestureDescription.createPinch(100, 100, 50, 75, 0, -1);
- fail("Missing exception for creating pinch with negative duration.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testZeroLengthPinch_shouldThrow() {
- try {
- GestureDescription.createPinch(100, 100, 50, 50, 0, 100);
- fail("Missing exception for creating pinch with zero length.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testPinch_negativeCenterX_shouldThrow() {
- try {
- GestureDescription.createPinch(-100, 100, 50, 75, 0, 100);
- fail("Missing exception for creating pinch with negative center x.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testPinch_negativeCenterY_shouldThrow() {
- try {
- GestureDescription.createPinch(100, -100, 50, 75, 0, 100);
- fail("Missing exception for creating pinch with negative center y.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testPinch_negativeStartSpacing_shouldThrow() {
- try {
- GestureDescription.createPinch(100, 100, -50, 75, 0, 100);
- fail("Missing exception for creating pinch with negative start spacing.");
- } catch (IllegalArgumentException e) {
- }
- }
-
- public void testPinch_negativeEndSpacing_shouldThrow() {
- try {
- GestureDescription.createPinch(100, 100, 50, -75, 0, 100);
- fail("Missing exception for creating pinch with negative end spacing.");
- } catch (IllegalArgumentException e) {
- }
- }
-
public void testStrokeDescriptionGetters_workAsExpected() {
int x = 100;
int startY = 100;
diff --git a/tests/admin/Android.mk b/tests/admin/Android.mk
index 7933004..e12cc94 100644
--- a/tests/admin/Android.mk
+++ b/tests/admin/Android.mk
@@ -20,7 +20,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctstestrunner mockito-target platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -37,4 +38,4 @@
include $(BUILD_CTS_PACKAGE)
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java b/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
index 9b80b33..81ea503 100644
--- a/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
+++ b/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -62,6 +63,7 @@
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
}
+ @Presubmit
public void testOnReceive() {
if (!mDeviceAdmin) {
Log.w(TAG, "Skipping testOnReceive");
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 57d22dd..543a385 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -122,52 +122,52 @@
}
}
- public void testSetDeviceLoggingEnabled_failIfNotDeviceOwner() {
+ public void testSetSecurityLoggingEnabled_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testSetDeviceLoggingEnabled_failIfNotDeviceOwner");
+ Log.w(TAG, "Skipping testSetSecurityLoggingEnabled_failIfNotDeviceOwner");
return;
}
try {
- mDevicePolicyManager.setDeviceLoggingEnabled(mComponent, true);
+ mDevicePolicyManager.setSecurityLoggingEnabled(mComponent, true);
fail("did not throw expected SecurityException");
} catch (SecurityException e) {
assertDeviceOwnerMessage(e.getMessage());
}
}
- public void testGetDeviceLoggingEnabled_failIfNotDeviceOwner() {
+ public void testIsSecurityLoggingEnabled_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testGetDeviceLoggingEnabled_failIfNotDeviceOwner");
+ Log.w(TAG, "Skipping testIsSecurityLoggingEnabled_failIfNotDeviceOwner");
return;
}
try {
- mDevicePolicyManager.getDeviceLoggingEnabled(mComponent);
+ mDevicePolicyManager.isSecurityLoggingEnabled(mComponent);
fail("did not throw expected SecurityException");
} catch (SecurityException e) {
assertDeviceOwnerMessage(e.getMessage());
}
}
- public void testRetrieveDeviceLogs_failIfNotDeviceOwner() {
+ public void testRetrieveSecurityLogs_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testRetrieveDeviceLogs_failIfNotDeviceOwner");
+ Log.w(TAG, "Skipping testRetrieveSecurityLogs_failIfNotDeviceOwner");
return;
}
try {
- mDevicePolicyManager.retrieveDeviceLogs(mComponent);
+ mDevicePolicyManager.retrieveSecurityLogs(mComponent);
fail("did not throw expected SecurityException");
} catch (SecurityException e) {
assertDeviceOwnerMessage(e.getMessage());
}
}
- public void testRetrievePreviousDeviceLogs_failIfNotDeviceOwner() {
+ public void testRetrievePreRebootSecurityLogs_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testRetrievePreviousDeviceLogs_failIfNotDeviceOwner");
+ Log.w(TAG, "Skipping testRetrievePreRebootSecurityLogs_failIfNotDeviceOwner");
return;
}
try {
- mDevicePolicyManager.retrievePreviousDeviceLogs(mComponent);
+ mDevicePolicyManager.retrievePreRebootSecurityLogs(mComponent);
fail("did not throw expected SecurityException");
} catch (SecurityException e) {
assertDeviceOwnerMessage(e.getMessage());
diff --git a/tests/app/AndroidTest.xml b/tests/app/AndroidTest.xml
index acbc9e7..6487bd7 100644
--- a/tests/app/AndroidTest.xml
+++ b/tests/app/AndroidTest.xml
@@ -23,7 +23,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.app.cts" />
- <option name="runtime-hint" value="3m8s" />
+ <option name="runtime-hint" value="6m38s" />
</test>
</configuration>
diff --git a/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java b/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java
new file mode 100644
index 0000000..6305adb
--- /dev/null
+++ b/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2008 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.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Instrumentation;
+import android.app.stubs.DialogStubActivity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnMultiChoiceClickListener;
+import android.cts.util.PollingCheck;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteCursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+import java.io.File;
+
+import static org.mockito.Mockito.*;
+
+@MediumTest
+public class AlertDialog_BuilderCursorTest
+ extends ActivityInstrumentationTestCase2<DialogStubActivity> {
+ private Builder mBuilder;
+ private Context mContext;
+ private Instrumentation mInstrumentation;
+ private AlertDialog mDialog;
+ private ListView mListView;
+
+ private static final String TEXT_COLUMN_NAME = "text";
+ private static final String CHECKED_COLUMN_NAME = "checked";
+
+ private String[] mTextContent;
+ private boolean[] mCheckedContent;
+
+ private String[] mProjectionWithChecked;
+ private String[] mProjectionWithoutChecked;
+
+ private SQLiteDatabase mDatabase;
+ private File mDatabaseFile;
+ private Cursor mCursor;
+
+ private OnClickListener mOnClickListener = mock(OnClickListener.class);
+
+ /**
+ * Multi-choice click listener that is registered on our {@link AlertDialog} when it's in
+ * multi-choide mode. Note that this needs to be a separate class that is also protected (not
+ * private) so that Mockito can "spy" on it.
+ */
+ protected class MultiChoiceClickListener implements OnMultiChoiceClickListener {
+ private boolean[] mCheckedTracker;
+
+ public MultiChoiceClickListener(boolean[] checkedTracker) {
+ mCheckedTracker = checkedTracker;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which,
+ boolean isChecked) {
+ // Update the underlying database with the new checked
+ // state for the specific row
+ mCursor.moveToPosition(which);
+ ContentValues valuesToUpdate = new ContentValues();
+ valuesToUpdate.put(CHECKED_COLUMN_NAME, isChecked ? 1 : 0);
+ mDatabase.update("test", valuesToUpdate,
+ TEXT_COLUMN_NAME + " = ?",
+ new String[] { mCursor.getString(1) } );
+ mCursor.requery();
+ mCheckedTracker[which] = isChecked;
+ }
+ }
+
+ public AlertDialog_BuilderCursorTest() {
+ super("android.app.stubs", DialogStubActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mBuilder = null;
+ mInstrumentation = getInstrumentation();
+ mContext = getActivity();
+ final Activity activity = getActivity();
+ new PollingCheck() {
+ @Override
+ protected boolean check() {
+ return activity.hasWindowFocus();
+ }
+ }.run();
+ mListView = null;
+ mDialog = null;
+
+ // Local test data for the tests
+ mTextContent = new String[] { "Adele", "Beyonce", "Ciara", "Dido" };
+ mCheckedContent = new boolean[] { false, false, true, false };
+
+ // Two projections - one with "checked" column and one without
+ mProjectionWithChecked = new String[] {
+ "_id", // 0
+ TEXT_COLUMN_NAME, // 1
+ CHECKED_COLUMN_NAME // 2
+ };
+ mProjectionWithoutChecked = new String[] {
+ "_id", // 0
+ TEXT_COLUMN_NAME // 1
+ };
+
+ File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE);
+ mDatabaseFile = new File(dbDir, "database_alert_dialog_test.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+ assertNotNull(mDatabase);
+ // Create and populate a test table
+ mDatabase.execSQL(
+ "CREATE TABLE test (_id INTEGER PRIMARY KEY, " + TEXT_COLUMN_NAME +
+ " TEXT, " + CHECKED_COLUMN_NAME + " INTEGER);");
+ for (int i = 0; i < mTextContent.length; i++) {
+ mDatabase.execSQL("INSERT INTO test (" + TEXT_COLUMN_NAME + ", " +
+ CHECKED_COLUMN_NAME + ") VALUES ('" + mTextContent[i] + "', " +
+ (mCheckedContent[i] ? "1" : "0") + ");");
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mCursor != null) {
+ // Close the cursor on the UI thread as the list view in the alert dialog
+ // will get notified of any change to the underlying cursor.
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mCursor.close();
+ mCursor = null;
+ }
+ });
+ }
+ if (mDatabase != null) {
+ mDatabase.close();
+ }
+ if (mDatabaseFile != null) {
+ mDatabaseFile.delete();
+ }
+
+ super.tearDown();
+ }
+
+ public void testSetCursor() throws Throwable {
+ // Use a projection without "checked" column
+ mCursor = mDatabase.query("test", mProjectionWithoutChecked,
+ null, null, null, null, null);
+ assertNotNull(mCursor);
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder = new Builder(mContext);
+ mBuilder.setCursor(mCursor, mOnClickListener, TEXT_COLUMN_NAME);
+ mDialog = mBuilder.show();
+ mListView = mDialog.getListView();
+ mListView.performItemClick(null, 0, 0);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ final SQLiteCursor selected = (SQLiteCursor) mListView.getSelectedItem();
+ assertEquals(mCursor.getString(1), selected.getString(1));
+ verify(mOnClickListener, times(1)).onClick(mDialog, 0);
+ verifyNoMoreInteractions(mOnClickListener);
+ }
+
+ public void testSetSingleChoiceItemsWithParamCursor() throws Throwable {
+ // Use a projection without "checked" column
+ mCursor = mDatabase.query("test", mProjectionWithoutChecked,
+ null, null, null, null, null);
+ assertNotNull(mCursor);
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder = new Builder(mContext);
+ mBuilder.setSingleChoiceItems(mCursor, 0, TEXT_COLUMN_NAME, mOnClickListener);
+ mDialog = mBuilder.show();
+ mListView = mDialog.getListView();
+ mListView.performItemClick(null, 0, 0);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ final SQLiteCursor selected = (SQLiteCursor) mListView.getSelectedItem();
+ assertEquals(mCursor.getString(1), selected.getString(1));
+ verify(mOnClickListener, times(1)).onClick(mDialog, 0);
+ verifyNoMoreInteractions(mOnClickListener);
+ }
+
+ public void testSetMultiChoiceItemsWithParamCursor() throws Throwable {
+ mCursor = mDatabase.query("test", mProjectionWithChecked,
+ null, null, null, null, null);
+ assertNotNull(mCursor);
+
+ final boolean[] checkedTracker = mCheckedContent.clone();
+ final OnMultiChoiceClickListener mockMultiChoiceClickListener =
+ spy(new MultiChoiceClickListener(checkedTracker));
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder = new Builder(mContext);
+ mBuilder.setMultiChoiceItems(mCursor, CHECKED_COLUMN_NAME, TEXT_COLUMN_NAME,
+ mockMultiChoiceClickListener);
+ mDialog = mBuilder.show();
+ mListView = mDialog.getListView();
+ mListView.performItemClick(null, 0, 0);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ SQLiteCursor selected = (SQLiteCursor) mListView.getSelectedItem();
+ assertEquals(mCursor.getString(0), selected.getString(0));
+ verify(mockMultiChoiceClickListener, times(1)).onClick(mDialog, 0, true);
+ // Verify that our multi-choice listener was invoked to update our tracker array
+ assertTrue(checkedTracker[0]);
+ assertFalse(checkedTracker[1]);
+ assertTrue(checkedTracker[2]);
+ assertFalse(checkedTracker[3]);
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mListView.performItemClick(null, 1, 1);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ selected = (SQLiteCursor) mListView.getSelectedItem();
+ assertEquals(mCursor.getString(1), selected.getString(1));
+ verify(mockMultiChoiceClickListener, times(1)).onClick(mDialog, 1, true);
+ // Verify that our multi-choice listener was invoked to update our tracker array
+ assertTrue(checkedTracker[0]);
+ assertTrue(checkedTracker[1]);
+ assertTrue(checkedTracker[2]);
+ assertFalse(checkedTracker[3]);
+
+ verifyNoMoreInteractions(mockMultiChoiceClickListener);
+ }
+}
diff --git a/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java b/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
index ff9d772..d13585a 100644
--- a/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
+++ b/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
@@ -22,8 +22,6 @@
import android.app.Instrumentation;
import android.app.stubs.DialogStubActivity;
import android.app.stubs.R;
-import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
@@ -33,10 +31,7 @@
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.res.TypedArray;
import android.cts.util.PollingCheck;
-import android.database.Cursor;
-import android.database.CursorWrapper;
import android.graphics.drawable.Drawable;
-import android.provider.Contacts.People;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.KeyEvent;
@@ -61,9 +56,6 @@
private AlertDialog mDialog;
private Button mButton;
private CharSequence mSelectedItem;
- private final String[] mPROJECTION = new String[] {
- People._ID, People.NAME
- };
private View mView;
private ListView mListView;
@@ -419,27 +411,6 @@
assertEquals(adapter, mListView.getAdapter());
}
- public void testSetCursor() throws Throwable {
- preparePeople();
- final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, mPROJECTION, null,
- null, null);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- mBuilder = new AlertDialog.Builder(mContext);
- mBuilder.setCursor(c, mOnClickListener, People.NAME);
- mDialog = mBuilder.show();
- mListView = mDialog.getListView();
- mListView.performItemClick(null, 0, 0);
- }
- });
- mInstrumentation.waitForIdleSync();
- final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
- assertEquals(c.getString(1), selected.getString(1));
- verify(mOnClickListener, times(1)).onClick(mDialog, 0);
- verifyNoMoreInteractions(mOnClickListener);
- }
-
public void testSetMultiChoiceItemsWithParamInt() throws Throwable {
final CharSequence[] items = mContext.getResources().getTextArray(
@@ -488,30 +459,6 @@
assertEquals(items[0], mListView.getItemAtPosition(0));
}
- public void testSetMultiChoiceItemsWithParamCursor() throws Throwable {
- preparePeople();
- final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, mPROJECTION, null,
- null, null);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- mBuilder = new AlertDialog.Builder(mContext);
- mBuilder.setMultiChoiceItems(c, People.NAME, People.NAME,
- mOnMultiChoiceClickListener);
- mDialog = mBuilder.show();
- mListView = mDialog.getListView();
- mListView.performItemClick(null, 0, 0);
- mListView.performItemClick(null, 1, 0);
- }
- });
- mInstrumentation.waitForIdleSync();
- final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
- assertEquals(c.getString(1), selected.getString(1));
- verify(mOnMultiChoiceClickListener, times(1)).onClick(mDialog, 0, true);
- verify(mOnMultiChoiceClickListener, times(1)).onClick(mDialog, 1, true);
- verifyNoMoreInteractions(mOnMultiChoiceClickListener);
- }
-
public void testSetSingleChoiceItemsWithParamInt() throws Throwable {
final CharSequence[] items = mContext.getResources().getTextArray(
R.array.difficultyLevel);
@@ -534,39 +481,6 @@
verifyNoMoreInteractions(mOnClickListener);
}
- private void preparePeople() {
- final ContentResolver mResolver = mContext.getContentResolver();
- mResolver.delete(People.CONTENT_URI, null, null);
- final ContentValues values = new ContentValues();
- values.put(People._ID, "1");
- values.put(People.NAME, "name");
- mResolver.insert(People.CONTENT_URI, values);
- }
-
- public void testSetSingleChoiceItemsWithParamCursor() throws Throwable {
- final String[] PROJECTION = new String[] {
- People._ID, People.NAME
- };
- preparePeople();
- final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, PROJECTION, null,
- null, null);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- mBuilder = new AlertDialog.Builder(mContext);
- mBuilder.setSingleChoiceItems(c, 0, People.NAME, mOnClickListener);
- mDialog = mBuilder.show();
- mListView = mDialog.getListView();
- mListView.performItemClick(null, 0, 0);
- }
- });
- mInstrumentation.waitForIdleSync();
- final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
- assertEquals(c.getString(1), selected.getString(1));
- verify(mOnClickListener, times(1)).onClick(mDialog, 0);
- verifyNoMoreInteractions(mOnClickListener);
- }
-
public void testSetSingleChoiceItemsWithParamCharSequence() throws Throwable {
final CharSequence[] items = mContext.getResources().getTextArray(
R.array.difficultyLevel);
diff --git a/tests/camera/AndroidManifest.xml b/tests/camera/AndroidManifest.xml
index 2b39fca..f8c4a8e 100644
--- a/tests/camera/AndroidManifest.xml
+++ b/tests/camera/AndroidManifest.xml
@@ -68,6 +68,13 @@
android:process=":camera2ActivityProcess">
</activity>
+ <activity android:name="android.hardware.multiprocess.camera.cts.MediaRecorderCameraActivity"
+ android:label="RemoteMediaRecorderCameraActivity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:process=":mediaRecorderCameraActivityProcess">
+ </activity>
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
index df15689..b54e1a22 100644
--- a/tests/camera/AndroidTest.xml
+++ b/tests/camera/AndroidTest.xml
@@ -21,5 +21,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.camera.cts" />
<option name="runtime-hint" value="12m7s" />
+ <!-- test-timeout unit is ms, value = 30 min -->
+ <option name="test-timeout" value="1800000" />
</test>
</configuration>
diff --git a/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
index e6a13ff..2969753 100644
--- a/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
@@ -95,8 +95,6 @@
super.setContext(context);
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
assertNotNull("Can't connect to camera manager!", mCameraManager);
-
- RenderScriptSingleton.setContext(context);
}
@Override
@@ -111,6 +109,8 @@
mCameraIterable = new CameraIterable();
mSizeIterable = new SizeIterable();
mResultIterable = new ResultIterable();
+
+ RenderScriptSingleton.setContext(getContext());
}
@Override
@@ -470,15 +470,14 @@
@Override
public void run(final Size size) throws CameraAccessException {
// Create a script graph that converts YUV to RGB
- final ScriptGraph scriptGraph = ScriptGraph.create()
+ try (ScriptGraph scriptGraph = ScriptGraph.create()
.configureInputWithSurface(size, YUV_420_888)
.chainScript(ScriptYuvToRgb.class)
- .buildGraph();
+ .buildGraph()) {
- if (VERBOSE) Log.v(TAG, "Prepared ScriptYuvToRgb for size " + size);
+ if (VERBOSE) Log.v(TAG, "Prepared ScriptYuvToRgb for size " + size);
- // Run the graph against camera input and validate we get some input
- try {
+ // Run the graph against camera input and validate we get some input
CaptureRequest request =
configureAndCreateRequestForSurface(scriptGraph.getInputSurface()).build();
@@ -495,8 +494,6 @@
});
stopCapture();
- } finally {
- scriptGraph.close();
}
}
});
@@ -536,36 +533,37 @@
final Size maxSize = getMaxSize(
getSupportedSizeForFormat(YUV_420_888, camera.getId(), mCameraManager));
- ScriptGraph scriptGraph = createGraphForYuvCroppedMeans(maxSize);
+ try (ScriptGraph scriptGraph = createGraphForYuvCroppedMeans(maxSize)) {
- CaptureRequest.Builder req =
- configureAndCreateRequestForSurface(scriptGraph.getInputSurface());
+ CaptureRequest.Builder req =
+ configureAndCreateRequestForSurface(scriptGraph.getInputSurface());
- // Take a shot with very low ISO and exposure time. Expect it to be black.
- int minimumSensitivity = staticInfo.getSensitivityMinimumOrDefault();
- long minimumExposure = staticInfo.getExposureMinimumOrDefault();
- setManualCaptureRequest(req, minimumSensitivity, minimumExposure);
+ // Take a shot with very low ISO and exposure time. Expect it to be black.
+ int minimumSensitivity = staticInfo.getSensitivityMinimumOrDefault();
+ long minimumExposure = staticInfo.getExposureMinimumOrDefault();
+ setManualCaptureRequest(req, minimumSensitivity, minimumExposure);
- CaptureRequest lowIsoExposureShot = req.build();
- captureSingleShotAndExecute(lowIsoExposureShot, scriptGraph);
+ CaptureRequest lowIsoExposureShot = req.build();
+ captureSingleShotAndExecute(lowIsoExposureShot, scriptGraph);
- float[] blackMeans = convertPixelYuvToRgb(scriptGraph.getOutputData());
+ float[] blackMeans = convertPixelYuvToRgb(scriptGraph.getOutputData());
- // Take a shot with very high ISO and exposure time. Expect it to be white.
- int maximumSensitivity = staticInfo.getSensitivityMaximumOrDefault();
- long maximumExposure = staticInfo.getExposureMaximumOrDefault();
- setManualCaptureRequest(req, maximumSensitivity, maximumExposure);
+ // Take a shot with very high ISO and exposure time. Expect it to be white.
+ int maximumSensitivity = staticInfo.getSensitivityMaximumOrDefault();
+ long maximumExposure = staticInfo.getExposureMaximumOrDefault();
+ setManualCaptureRequest(req, maximumSensitivity, maximumExposure);
- CaptureRequest highIsoExposureShot = req.build();
- captureSingleShotAndExecute(highIsoExposureShot, scriptGraph);
+ CaptureRequest highIsoExposureShot = req.build();
+ captureSingleShotAndExecute(highIsoExposureShot, scriptGraph);
- float[] whiteMeans = convertPixelYuvToRgb(scriptGraph.getOutputData());
+ float[] whiteMeans = convertPixelYuvToRgb(scriptGraph.getOutputData());
- // low iso + low exposure (first shot)
- assertArrayWithinUpperBound("Black means too high", blackMeans, THRESHOLD_LOW);
+ // low iso + low exposure (first shot)
+ assertArrayWithinUpperBound("Black means too high", blackMeans, THRESHOLD_LOW);
- // high iso + high exposure (second shot)
- assertArrayWithinLowerBound("White means too low", whiteMeans, THRESHOLD_HIGH);
+ // high iso + high exposure (second shot)
+ assertArrayWithinLowerBound("White means too low", whiteMeans, THRESHOLD_HIGH);
+ }
}
});
}
@@ -608,48 +606,49 @@
sensitivities[i] = sensitivityMin + delta * i;
}
- ScriptGraph scriptGraph = createGraphForYuvCroppedMeans(maxSize);
+ try (ScriptGraph scriptGraph = createGraphForYuvCroppedMeans(maxSize)) {
- CaptureRequest.Builder req =
- configureAndCreateRequestForSurface(scriptGraph.getInputSurface());
+ CaptureRequest.Builder req =
+ configureAndCreateRequestForSurface(scriptGraph.getInputSurface());
- // Take burst shots with increasing sensitivity one after other.
- for (int i = 0; i < NUM_STEPS; ++i) {
- setManualCaptureRequest(req, sensitivities[i], EXPOSURE_TIME_NS);
- captureSingleShotAndExecute(req.build(), scriptGraph);
- float[] means = convertPixelYuvToRgb(scriptGraph.getOutputData());
- rgbMeans.add(means);
+ // Take burst shots with increasing sensitivity one after other.
+ for (int i = 0; i < NUM_STEPS; ++i) {
+ setManualCaptureRequest(req, sensitivities[i], EXPOSURE_TIME_NS);
+ captureSingleShotAndExecute(req.build(), scriptGraph);
+ float[] means = convertPixelYuvToRgb(scriptGraph.getOutputData());
+ rgbMeans.add(means);
- if (VERBOSE) {
- Log.v(TAG, "testParamSensitivity - captured image " + i +
- " with RGB means: " + Arrays.toString(means));
+ if (VERBOSE) {
+ Log.v(TAG, "testParamSensitivity - captured image " + i +
+ " with RGB means: " + Arrays.toString(means));
+ }
}
- }
- // Test that every consecutive image gets brighter.
- for (int i = 0; i < rgbMeans.size() - 1; ++i) {
- float[] curMeans = rgbMeans.get(i);
- float[] nextMeans = rgbMeans.get(i+1);
+ // Test that every consecutive image gets brighter.
+ for (int i = 0; i < rgbMeans.size() - 1; ++i) {
+ float[] curMeans = rgbMeans.get(i);
+ float[] nextMeans = rgbMeans.get(i+1);
- assertArrayNotGreater(
- String.format("Shot with sensitivity %d should not have higher " +
- "average means than shot with sensitivity %d",
- sensitivities[i], sensitivities[i+1]),
- curMeans, nextMeans);
- }
+ assertArrayNotGreater(
+ String.format("Shot with sensitivity %d should not have higher " +
+ "average means than shot with sensitivity %d",
+ sensitivities[i], sensitivities[i+1]),
+ curMeans, nextMeans);
+ }
- // Test the min-max diff and ratios are within expected thresholds
- float[] lastMeans = rgbMeans.get(NUM_STEPS - 1);
- float[] firstMeans = rgbMeans.get(/*location*/0);
- for (int i = 0; i < RGB_CHANNELS; ++i) {
- assertTrue(
- String.format("Sensitivity max-min diff too small (max=%f, min=%f)",
- lastMeans[i], firstMeans[i]),
- lastMeans[i] - firstMeans[i] > THRESHOLD_MAX_MIN_DIFF);
- assertTrue(
- String.format("Sensitivity max-min ratio too small (max=%f, min=%f)",
- lastMeans[i], firstMeans[i]),
- lastMeans[i] / firstMeans[i] > THRESHOLD_MAX_MIN_RATIO);
+ // Test the min-max diff and ratios are within expected thresholds
+ float[] lastMeans = rgbMeans.get(NUM_STEPS - 1);
+ float[] firstMeans = rgbMeans.get(/*location*/0);
+ for (int i = 0; i < RGB_CHANNELS; ++i) {
+ assertTrue(
+ String.format("Sensitivity max-min diff too small (max=%f, min=%f)",
+ lastMeans[i], firstMeans[i]),
+ lastMeans[i] - firstMeans[i] > THRESHOLD_MAX_MIN_DIFF);
+ assertTrue(
+ String.format("Sensitivity max-min ratio too small (max=%f, min=%f)",
+ lastMeans[i], firstMeans[i]),
+ lastMeans[i] / firstMeans[i] > THRESHOLD_MAX_MIN_RATIO);
+ }
}
}
});
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
index 8324490..35e792b 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -2079,7 +2079,8 @@
exifFocalLength, EXIF_FOCAL_LENGTH_ERROR_MARGIN);
// More checks for focal length.
collector.expectEquals("Exif focal length should match capture result",
- validateFocalLength(result, staticInfo, collector), exifFocalLength);
+ validateFocalLength(result, staticInfo, collector),
+ exifFocalLength, EXIF_FOCAL_LENGTH_ERROR_MARGIN);
// TAG_EXPOSURE_TIME
// ExifInterface API gives exposure time value in the form of float instead of rational
@@ -2110,7 +2111,8 @@
apertureValue, EXIF_APERTURE_ERROR_MARGIN);
// More checks for aperture.
collector.expectEquals("Exif aperture length should match capture result",
- validateAperture(result, staticInfo, collector), apertureValue);
+ validateAperture(result, staticInfo, collector),
+ apertureValue, EXIF_APERTURE_ERROR_MARGIN);
}
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java b/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java
index a9f0008..02bb348 100644
--- a/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java
@@ -97,6 +97,8 @@
@Override
protected void setUp() throws Exception {
+ RenderScriptSingleton.setContext(getContext());
+
super.setUp();
}
@@ -110,8 +112,6 @@
@Override
public synchronized void setContext(Context context) {
super.setContext(context);
-
- RenderScriptSingleton.setContext(context);
}
/**
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 81767a6..4d9a145 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -539,11 +539,22 @@
(maxJpegSize.getWidth() <= maxYuvSize.getWidth() &&
maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false;
+ float croppedWidth = (float)sensorSize.getWidth();
+ float croppedHeight = (float)sensorSize.getHeight();
+ float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight();
+ float maxYuvAspectRatio = (float)maxYuvSize.getWidth() / (float)maxYuvSize.getHeight();
+ if (sensorAspectRatio < maxYuvAspectRatio) {
+ croppedHeight = (float)sensorSize.getWidth() / maxYuvAspectRatio;
+ } else if (sensorAspectRatio > maxYuvAspectRatio) {
+ croppedWidth = (float)sensorSize.getHeight() * maxYuvAspectRatio;
+ }
+ Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight);
+
boolean maxYuvMatchSensor =
- (maxYuvSize.getWidth() <= sensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) &&
- maxYuvSize.getWidth() >= sensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) &&
- maxYuvSize.getHeight() <= sensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
- maxYuvSize.getHeight() >= sensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
+ (maxYuvSize.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) &&
+ maxYuvSize.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) &&
+ maxYuvSize.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
+ maxYuvSize.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
// No need to do null check since framework will generate the key if HAL don't supply
boolean haveAeLock = CameraTestUtils.getValueNotNull(
@@ -627,8 +638,9 @@
haveFastSyncLatency);
assertTrue(
String.format("BURST-capable camera device %s max YUV size %s should be" +
- "close to active array size %s",
- mIds[counter], maxYuvSize.toString(), sensorSize.toString()),
+ "close to active array size %s or cropped active array size %s",
+ mIds[counter], maxYuvSize.toString(), sensorSize.toString(),
+ croppedSensorSize.toString()),
maxYuvMatchSensor);
assertTrue(
String.format("BURST-capable camera device %s does not support AE lock",
diff --git a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
index 3f2d886..8ee0a41 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -116,9 +116,19 @@
// Max jpeg resolution must be very close to sensor resolution
Size[] jpegSizes = mStaticInfo.getJpegOutputSizesChecked();
Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
+ float croppedWidth = (float)sensorSize.getWidth();
+ float croppedHeight = (float)sensorSize.getHeight();
+ float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight();
+ float maxJpegAspectRatio = (float)maxJpegSize.getWidth() / (float)maxJpegSize.getHeight();
+ if (sensorAspectRatio < maxJpegAspectRatio) {
+ croppedHeight = (float)sensorSize.getWidth() / maxJpegAspectRatio;
+ } else if (sensorAspectRatio > maxJpegAspectRatio) {
+ croppedWidth = (float)sensorSize.getHeight() * maxJpegAspectRatio;
+ }
+ Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight);
mCollector.expectSizesAreSimilar(
- "Active array size and max JPEG size should be similar",
- sensorSize, maxJpegSize, SIZE_ERROR_MARGIN);
+ "Active array size or cropped active array size and max JPEG size should be similar",
+ croppedSensorSize, maxJpegSize, SIZE_ERROR_MARGIN);
}
// TODO: test all the keys mandatory for all capability devices.
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index ce229b1..a9b4ad2 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -402,7 +402,7 @@
continue;
}
takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
- /*addAeTriggerCancel*/true, /*allocateBitmap*/true);
+ /*addAeTriggerCancel*/false, /*allocateBitmap*/true);
} finally {
closeDevice();
closeImageReader();
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
index 9f1ae03..834d37cf 100644
--- a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
@@ -147,93 +147,7 @@
* Test basic eviction scenarios for the Camera1 API.
*/
public void testCamera1ActivityEviction() throws Throwable {
-
- // Open a camera1 client in the main CTS process's activity
- final Camera.ErrorCallback mockErrorCb1 = mock(Camera.ErrorCallback.class);
- final boolean[] skip = {false};
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- // Open camera
- mCamera = Camera.open();
- if (mCamera == null) {
- skip[0] = true;
- } else {
- mCamera.setErrorCallback(mockErrorCb1);
- }
- notifyFromUI();
- }
- });
- waitForUI();
-
- if (skip[0]) {
- Log.i(TAG, "Skipping testCamera1ActivityEviction, device has no cameras.");
- return;
- }
-
- verifyZeroInteractions(mockErrorCb1);
-
- startRemoteProcess(Camera1Activity.class, "camera1ActivityProcess");
-
- // Make sure camera was setup correctly in remote activity
- List<ErrorLoggingService.LogEvent> events = null;
- try {
- events = mErrorServiceConnection.getLog(SETUP_TIMEOUT,
- TestConstants.EVENT_CAMERA_CONNECT);
- } finally {
- if (events != null) assertOnly(TestConstants.EVENT_CAMERA_CONNECT, events);
- }
-
- Thread.sleep(WAIT_TIME);
-
- // Ensure UI thread has a chance to process callbacks.
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- Log.i("CTS", "Did something on UI thread.");
- notifyFromUI();
- }
- });
- waitForUI();
-
- // Make sure we received correct callback in error listener, and nothing else
- verify(mockErrorCb1, only()).onError(eq(Camera.CAMERA_ERROR_EVICTED), isA(Camera.class));
- mCamera = null;
-
- // Try to open the camera again (even though other TOP process holds the camera).
- final boolean[] pass = {false};
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- // Open camera
- try {
- mCamera = Camera.open();
- } catch (RuntimeException e) {
- pass[0] = true;
- }
- notifyFromUI();
- }
- });
- waitForUI();
-
- assertTrue("Did not receive exception when opening camera while camera is held by a" +
- " higher priority client process.", pass[0]);
-
- // Verify that attempting to open the camera didn't cause anything weird to happen in the
- // other process.
- List<ErrorLoggingService.LogEvent> eventList2 = null;
- boolean timeoutExceptionHit = false;
- try {
- eventList2 = mErrorServiceConnection.getLog(EVICTION_TIMEOUT);
- } catch (TimeoutException e) {
- timeoutExceptionHit = true;
- }
-
- assertNone("Remote camera service received invalid events: ", eventList2);
- assertTrue("Remote camera service exited early", timeoutExceptionHit);
- android.os.Process.killProcess(mProcessPid);
- mProcessPid = -1;
- forceCtsActivityToTop();
+ testAPI1ActivityEviction(Camera1Activity.class, "camera1ActivityProcess");
}
/**
@@ -342,6 +256,114 @@
forceCtsActivityToTop();
}
+
+ /**
+ * Test basic eviction scenarios for camera used in MediaRecoder
+ */
+ public void testMediaRecorderCameraActivityEviction() throws Throwable {
+ testAPI1ActivityEviction(MediaRecorderCameraActivity.class,
+ "mediaRecorderCameraActivityProcess");
+ }
+
+ /**
+ * Test basic eviction scenarios for Camera1 API.
+ *
+ * This test will open camera, create a higher priority process to run the specified activity,
+ * open camera again, and verify the right clients are evicted.
+ *
+ * @param activityKlass An activity to run in a higher priority process.
+ * @param processName The process name.
+ */
+ private void testAPI1ActivityEviction (java.lang.Class<?> activityKlass, String processName)
+ throws Throwable {
+ // Open a camera1 client in the main CTS process's activity
+ final Camera.ErrorCallback mockErrorCb1 = mock(Camera.ErrorCallback.class);
+ final boolean[] skip = {false};
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Open camera
+ mCamera = Camera.open();
+ if (mCamera == null) {
+ skip[0] = true;
+ } else {
+ mCamera.setErrorCallback(mockErrorCb1);
+ }
+ notifyFromUI();
+ }
+ });
+ waitForUI();
+
+ if (skip[0]) {
+ Log.i(TAG, "Skipping testCamera1ActivityEviction, device has no cameras.");
+ return;
+ }
+
+ verifyZeroInteractions(mockErrorCb1);
+
+ startRemoteProcess(activityKlass, processName);
+
+ // Make sure camera was setup correctly in remote activity
+ List<ErrorLoggingService.LogEvent> events = null;
+ try {
+ events = mErrorServiceConnection.getLog(SETUP_TIMEOUT,
+ TestConstants.EVENT_CAMERA_CONNECT);
+ } finally {
+ if (events != null) assertOnly(TestConstants.EVENT_CAMERA_CONNECT, events);
+ }
+
+ Thread.sleep(WAIT_TIME);
+
+ // Ensure UI thread has a chance to process callbacks.
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Log.i("CTS", "Did something on UI thread.");
+ notifyFromUI();
+ }
+ });
+ waitForUI();
+
+ // Make sure we received correct callback in error listener, and nothing else
+ verify(mockErrorCb1, only()).onError(eq(Camera.CAMERA_ERROR_EVICTED), isA(Camera.class));
+ mCamera = null;
+
+ // Try to open the camera again (even though other TOP process holds the camera).
+ final boolean[] pass = {false};
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Open camera
+ try {
+ mCamera = Camera.open();
+ } catch (RuntimeException e) {
+ pass[0] = true;
+ }
+ notifyFromUI();
+ }
+ });
+ waitForUI();
+
+ assertTrue("Did not receive exception when opening camera while camera is held by a" +
+ " higher priority client process.", pass[0]);
+
+ // Verify that attempting to open the camera didn't cause anything weird to happen in the
+ // other process.
+ List<ErrorLoggingService.LogEvent> eventList2 = null;
+ boolean timeoutExceptionHit = false;
+ try {
+ eventList2 = mErrorServiceConnection.getLog(EVICTION_TIMEOUT);
+ } catch (TimeoutException e) {
+ timeoutExceptionHit = true;
+ }
+
+ assertNone("Remote camera service received invalid events: ", eventList2);
+ assertTrue("Remote camera service exited early", timeoutExceptionHit);
+ android.os.Process.killProcess(mProcessPid);
+ mProcessPid = -1;
+ forceCtsActivityToTop();
+ }
+
/**
* Ensure the CTS activity becomes foreground again instead of launcher.
*/
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java
new file mode 100644
index 0000000..0558800
--- /dev/null
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java
@@ -0,0 +1,143 @@
+/*
+ * 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.hardware.multiprocess.camera.cts;
+
+import android.app.Activity;
+import android.camera.cts.R;
+import android.media.MediaRecorder;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+
+import java.io.File;
+
+/**
+ * Activity implementing basic access of camera using MediaRecorder API.
+ *
+ * <p />
+ * This will log all errors to {@link android.hardware.multiprocess.camera.cts.ErrorLoggingService}.
+ */
+public class MediaRecorderCameraActivity extends Activity implements SurfaceHolder.Callback {
+ private static final String TAG = "MediaRecorderCameraActivity";
+
+ private static final int VIDEO_WIDTH = 640;
+ private static final int VIDEO_HEIGHT = 480;
+ private static final int LAYOUT_WIDTH = VIDEO_WIDTH;
+ private static final int LAYOUT_HEIGHT = VIDEO_HEIGHT;
+
+ private final String OUTPUT_PATH = new File(Environment.getExternalStorageDirectory(),
+ "record.out").getAbsolutePath();
+
+ private File mOutFile;
+ private SurfaceView mSurfaceView;
+ private ErrorLoggingService.ErrorServiceConnection mErrorServiceConnection;
+ private MediaRecorder mMediaRecorder;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Log.i(TAG, "onCreate called.");
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.surface_view);
+
+ mErrorServiceConnection = new ErrorLoggingService.ErrorServiceConnection(this);
+ mErrorServiceConnection.start();
+
+ mMediaRecorder = new MediaRecorder();
+ }
+
+ @Override
+ protected void onResume() {
+ Log.i(TAG, "onResume called.");
+ super.onResume();
+ try {
+
+ mSurfaceView = (SurfaceView)this.findViewById(R.id.surface_view);
+ ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
+ lp.width = LAYOUT_WIDTH;
+ lp.height = LAYOUT_HEIGHT;
+ mSurfaceView.setLayoutParams(lp);
+
+ SurfaceHolder holder = mSurfaceView.getHolder();
+ holder.setFixedSize(LAYOUT_WIDTH, LAYOUT_HEIGHT);
+ holder.addCallback(this);
+
+ } catch (Throwable e) {
+ mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_ERROR, TAG +
+ " camera exception during connection: " + e);
+ Log.e(TAG, "Runtime error: " + e);
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ Log.i(TAG, "onPause called.");
+ super.onPause();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.i(TAG, "onDestroy called.");
+ super.onDestroy();
+ if (mErrorServiceConnection != null) {
+ mErrorServiceConnection.stop();
+ mErrorServiceConnection = null;
+ }
+
+ if (mOutFile != null && mOutFile.exists()) {
+ mOutFile.delete();
+ }
+
+ if (mMediaRecorder != null) {
+ mMediaRecorder.stop();
+ mMediaRecorder.release();
+ }
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ try {
+ mOutFile = new File(OUTPUT_PATH);
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
+ mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
+ mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+ mMediaRecorder.setOutputFile(OUTPUT_PATH);
+ mMediaRecorder.prepare();
+ mMediaRecorder.start();
+
+ mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_CONNECT,
+ TAG + " camera connected");
+ } catch (Throwable e) {
+ mErrorServiceConnection.logAsync(TestConstants.EVENT_CAMERA_ERROR, TAG +
+ " camera exception during connection: " + e);
+ Log.e(TAG, "Runtime error: " + e);
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 185fc56..56475fd 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -31,13 +31,6 @@
bug: 17595050
},
{
- description: "test fails on devices with no telephony",
- names: [
- "android.calllog.cts.CallLogBackupTest#testSingleCallBackup"
- ],
- bug: 23776099
-},
-{
description: "test fails on some devices",
names: [
"android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput",
@@ -342,5 +335,22 @@
"android.security.cts.MediaCryptoTest#testMediaCryptoWidevine"
],
bug: 27218502
+},
+{
+ description: "Still investigating this, root cause unknown yet",
+ bug: 27578806,
+ names: ["com.android.cts.cpptools.RunAsHostTest#testRunAs"]
+},
+{
+ description: "Some SensorBatchingTest cases fails due to test imperection",
+ names: [
+ "android.hardware.cts.SensorBatchingTests#testGyroscope_fastest_batching",
+ "android.hardware.cts.SensorBatchingTests#testGravity_50hz_batching",
+ "android.hardware.cts.SensorBatchingTests#testGravity_fastest_batching",
+ "android.hardware.cts.SensorBatchingTests#testLinearAcceleration_50hz_batching",
+ "android.hardware.cts.SensorBatchingTests#testLinearAcceleration_fastest_batching",
+ "android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_batching"
+ ],
+ bug: 27534791
}
]
diff --git a/tests/filesystem/AndroidTest.xml b/tests/filesystem/AndroidTest.xml
index 1962357..d05134d 100644
--- a/tests/filesystem/AndroidTest.xml
+++ b/tests/filesystem/AndroidTest.xml
@@ -20,6 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.filesystem.cts" />
- <option name="runtime-hint" value="9m" />
+ <option name="runtime-hint" value="22m48s" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/automotive/Android.mk b/tests/fragment/Android.mk
similarity index 71%
copy from tests/tests/automotive/Android.mk
copy to tests/fragment/Android.mk
index abef2ac..2352564 100644
--- a/tests/tests/automotive/Android.mk
+++ b/tests/fragment/Android.mk
@@ -16,17 +16,19 @@
include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsAutomotiveTestCases
+LOCAL_PACKAGE_NAME := CtsFragmentTestCases
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
+# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_DEX_PREOPT := false
-LOCAL_JAVA_LIBRARIES := android.car
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -35,4 +37,4 @@
LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_PACKAGE)
diff --git a/tests/fragment/AndroidManifest.xml b/tests/fragment/AndroidManifest.xml
new file mode 100644
index 0000000..05027b5
--- /dev/null
+++ b/tests/fragment/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?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.fragment.cts">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".FragmentTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.fragment.cts"
+ android:label="CTS tests of android.app Fragments" />
+
+</manifest>
+
diff --git a/tests/tests/automotive/AndroidTest.xml b/tests/fragment/AndroidTest.xml
similarity index 81%
copy from tests/tests/automotive/AndroidTest.xml
copy to tests/fragment/AndroidTest.xml
index b4af1f5..f3e302a 100644
--- a/tests/tests/automotive/AndroidTest.xml
+++ b/tests/fragment/AndroidTest.xml
@@ -13,12 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for CTS Automotive test cases">
+<configuration description="Configuration for app.usage Tests">
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsAutomotiveTestCases.apk" />
+ <option name="test-file-name" value="CtsFragmentTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.support.car.cts" />
+ <option name="package" value="android.fragment.cts" />
</test>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/tests/fragment/res/layout/strict_view_fragment.xml b/tests/fragment/res/layout/strict_view_fragment.xml
new file mode 100644
index 0000000..324f8d0
--- /dev/null
+++ b/tests/fragment/res/layout/strict_view_fragment.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 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.
+*/
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/text1" />
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
new file mode 100644
index 0000000..01c4e70
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -0,0 +1,234 @@
+/*
+ * 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.fragment.cts;
+
+import android.app.FragmentManager;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.*;
+
+@RunWith(AndroidJUnit4.class)
+public class FragmentLifecycleTest {
+
+ @Rule
+ public ActivityTestRule<FragmentTestActivity> mActivityRule =
+ new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+ @Test
+ @MediumTest
+ public void basicLifecycle() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+ final StrictFragment strictFragment = new StrictFragment();
+
+ // Add fragment; StrictFragment will throw if it detects any violation
+ // in standard lifecycle method ordering or expected preconditions.
+ fm.beginTransaction().add(strictFragment, "EmptyHeadless").commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment is not added", strictFragment.isAdded());
+ assertFalse("fragment is detached", strictFragment.isDetached());
+ assertTrue("fragment is not resumed", strictFragment.isResumed());
+
+ // Test removal as well; StrictFragment will throw here too.
+ fm.beginTransaction().remove(strictFragment).commit();
+ executePendingTransactions(fm);
+
+ assertFalse("fragment is added", strictFragment.isAdded());
+ assertFalse("fragment is resumed", strictFragment.isResumed());
+
+ // This one is perhaps counterintuitive; "detached" means specifically detached
+ // but still managed by a FragmentManager. The .remove call above
+ // should not enter this state.
+ assertFalse("fragment is detached", strictFragment.isDetached());
+ }
+
+ @Test
+ @MediumTest
+ public void detachment() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+ final StrictFragment f1 = new StrictFragment();
+ final StrictFragment f2 = new StrictFragment();
+
+ fm.beginTransaction().add(f1, "1").add(f2, "2").commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+ assertTrue("fragment 2 is not added", f2.isAdded());
+
+ // Test detaching fragments using StrictFragment to throw on errors.
+ fm.beginTransaction().detach(f1).detach(f2).commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not detached", f1.isDetached());
+ assertTrue("fragment 2 is not detached", f2.isDetached());
+ assertFalse("fragment 1 is added", f1.isAdded());
+ assertFalse("fragment 2 is added", f2.isAdded());
+
+ // Only reattach f1; leave v2 detached.
+ fm.beginTransaction().attach(f1).commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+ assertFalse("fragment 1 is detached", f1.isDetached());
+ assertTrue("fragment 2 is not detached", f2.isDetached());
+
+ // Remove both from the FragmentManager.
+ fm.beginTransaction().remove(f1).remove(f2).commit();
+ executePendingTransactions(fm);
+
+ assertFalse("fragment 1 is added", f1.isAdded());
+ assertFalse("fragment 2 is added", f2.isAdded());
+ assertFalse("fragment 1 is detached", f1.isDetached());
+ assertFalse("fragment 2 is detached", f2.isDetached());
+ }
+
+ @Test
+ @MediumTest
+ public void basicBackStack() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+ final StrictFragment f1 = new StrictFragment();
+ final StrictFragment f2 = new StrictFragment();
+
+ // Add a fragment normally to set up
+ fm.beginTransaction().add(f1, "1").commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+
+ // Remove the first one and add a second. We're not using replace() here since
+ // these fragments are headless and as of this test writing, replace() only works
+ // for fragments with views and a container view id.
+ // Add it to the back stack so we can pop it afterwards.
+ fm.beginTransaction().remove(f1).add(f2, "2").addToBackStack("stack1").commit();
+ executePendingTransactions(fm);
+
+ assertFalse("fragment 1 is added", f1.isAdded());
+ assertTrue("fragment 2 is not added", f2.isAdded());
+
+ // Test popping the stack
+ fm.popBackStack();
+ executePendingTransactions(fm);
+
+ assertFalse("fragment 2 is added", f2.isAdded());
+ assertTrue("fragment 1 is not added", f1.isAdded());
+ }
+
+ @Test
+ @MediumTest
+ public void attachBackStack() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+ final StrictFragment f1 = new StrictFragment();
+ final StrictFragment f2 = new StrictFragment();
+
+ // Add a fragment normally to set up
+ fm.beginTransaction().add(f1, "1").commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+
+ fm.beginTransaction().detach(f1).add(f2, "2").addToBackStack("stack1").commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not detached", f1.isDetached());
+ assertFalse("fragment 2 is detached", f2.isDetached());
+ assertFalse("fragment 1 is added", f1.isAdded());
+ assertTrue("fragment 2 is not added", f2.isAdded());
+ }
+
+ @Test
+ @MediumTest
+ public void viewLifecycle() throws Throwable {
+ // Test basic lifecycle when the fragment creates a view
+
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+ final StrictViewFragment f1 = new StrictViewFragment();
+
+ fm.beginTransaction().add(android.R.id.content, f1).commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+ final View view = f1.getView();
+ assertNotNull("fragment 1 returned null from getView", view);
+ assertTrue("fragment 1's view is not attached to a window", view.isAttachedToWindow());
+
+ fm.beginTransaction().remove(f1).commit();
+ executePendingTransactions(fm);
+
+ assertFalse("fragment 1 is added", f1.isAdded());
+ assertNull("fragment 1 returned non-null from getView after removal", f1.getView());
+ assertFalse("fragment 1's previous view is still attached to a window",
+ view.isAttachedToWindow());
+ }
+
+ @Test
+ @MediumTest
+ public void viewReplace() throws Throwable {
+ // Replace one view with another, then reverse it with the back stack
+
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+ final StrictViewFragment f1 = new StrictViewFragment();
+ final StrictViewFragment f2 = new StrictViewFragment();
+
+ fm.beginTransaction().add(android.R.id.content, f1).commit();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+
+ View origView1 = f1.getView();
+ assertNotNull("fragment 1 returned null view", origView1);
+ assertTrue("fragment 1's view not attached", origView1.isAttachedToWindow());
+
+ fm.beginTransaction().replace(android.R.id.content, f2).addToBackStack("stack1").commit();
+ executePendingTransactions(fm);
+
+ assertFalse("fragment 1 is added", f1.isAdded());
+ assertTrue("fragment 2 is added", f2.isAdded());
+ assertNull("fragment 1 returned non-null view", f1.getView());
+ assertFalse("fragment 1's old view still attached", origView1.isAttachedToWindow());
+ View origView2 = f2.getView();
+ assertNotNull("fragment 2 returned null view", origView2);
+ assertTrue("fragment 2's view not attached", origView2.isAttachedToWindow());
+
+ fm.popBackStack();
+ executePendingTransactions(fm);
+
+ assertTrue("fragment 1 is not added", f1.isAdded());
+ assertFalse("fragment 2 is added", f2.isAdded());
+ assertNull("fragment 2 returned non-null view", f2.getView());
+ assertFalse("fragment 2's view still attached", origView2.isAttachedToWindow());
+ View newView1 = f1.getView();
+ assertNotSame("fragment 1 had same view from last attachment", origView1, newView1);
+ assertTrue("fragment 1's view not attached", newView1.isAttachedToWindow());
+ }
+
+ private void executePendingTransactions(final FragmentManager fm) throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ fm.executePendingTransactions();
+ }
+ });
+ }
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTestActivity.java b/tests/fragment/src/android/fragment/cts/FragmentTestActivity.java
new file mode 100644
index 0000000..fd26d0a
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestActivity.java
@@ -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.
+ */
+
+
+package android.fragment.cts;
+
+import android.app.Activity;
+
+public class FragmentTestActivity extends Activity {
+}
diff --git a/tests/fragment/src/android/fragment/cts/StrictFragment.java b/tests/fragment/src/android/fragment/cts/StrictFragment.java
new file mode 100644
index 0000000..f0c4a8a
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/StrictFragment.java
@@ -0,0 +1,175 @@
+/*
+ * 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.fragment.cts;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * This fragment watches its primary lifecycle events and throws IllegalStateException
+ * if any of them are called out of order or from a bad/unexpected state.
+ */
+public class StrictFragment extends Fragment {
+ public static final int DETACHED = 0;
+ public static final int ATTACHED = 1;
+ public static final int CREATED = 2;
+ public static final int ACTIVITY_CREATED = 3;
+ public static final int STARTED = 4;
+ public static final int RESUMED = 5;
+
+ int mState;
+
+ boolean mCalledOnAttach, mCalledOnCreate, mCalledOnActivityCreated,
+ mCalledOnStart, mCalledOnResume, mCalledOnSaveInstanceState,
+ mCalledOnPause, mCalledOnStop, mCalledOnDestroy, mCalledOnDetach;
+
+ static String stateToString(int state) {
+ switch (state) {
+ case DETACHED: return "DETACHED";
+ case ATTACHED: return "ATTACHED";
+ case CREATED: return "CREATED";
+ case ACTIVITY_CREATED: return "ACTIVITY_CREATED";
+ case STARTED: return "STARTED";
+ case RESUMED: return "RESUMED";
+ }
+ return "(unknown " + state + ")";
+ }
+
+ public void checkGetActivity() {
+ if (getActivity() == null) {
+ throw new IllegalStateException("getActivity() returned null at unexpected time");
+ }
+ }
+
+ public void checkState(String caller, int... expected) {
+ if (expected == null || expected.length == 0) {
+ throw new IllegalArgumentException("must supply at least one expected state");
+ }
+ for (int expect : expected) {
+ if (mState == expect) {
+ return;
+ }
+ }
+ final StringBuilder expectString = new StringBuilder(stateToString(expected[0]));
+ for (int i = 1; i < expected.length; i++) {
+ expectString.append(" or ").append(stateToString(expected[i]));
+ }
+ throw new IllegalStateException(caller + " called while fragment was "
+ + stateToString(mState) + "; expected " + expectString.toString());
+ }
+
+ public void checkStateAtLeast(String caller, int minState) {
+ if (mState < minState) {
+ throw new IllegalStateException(caller + " called while fragment was "
+ + stateToString(mState) + "; expected at least " + stateToString(minState));
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mCalledOnAttach = true;
+ checkState("onAttach", DETACHED);
+ mState = ATTACHED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (mCalledOnCreate) {
+ throw new IllegalStateException("onCreate called more than once");
+ }
+ mCalledOnCreate = true;
+ checkState("onCreate", ATTACHED);
+ mState = CREATED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mCalledOnActivityCreated = true;
+ checkState("onActivityCreated", ATTACHED, CREATED);
+ mState = ACTIVITY_CREATED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mCalledOnStart = true;
+ checkState("onStart", ACTIVITY_CREATED);
+ mState = STARTED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mCalledOnResume = true;
+ checkState("onResume", STARTED);
+ mState = RESUMED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mCalledOnSaveInstanceState = true;
+ checkGetActivity();
+ checkStateAtLeast("onSaveInstanceState", STARTED);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mCalledOnPause = true;
+ checkState("onPause", RESUMED);
+ mState = STARTED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mCalledOnStop = true;
+ checkState("onStop", STARTED);
+ mState = CREATED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mCalledOnDestroy = true;
+ checkState("onDestroy", CREATED);
+ mState = ATTACHED;
+ checkGetActivity();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mCalledOnDetach = true;
+ checkState("onDestroy", CREATED, ATTACHED);
+ mState = DETACHED;
+ checkGetActivity();
+ }
+}
diff --git a/tests/fragment/src/android/fragment/cts/StrictViewFragment.java b/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
new file mode 100644
index 0000000..8c0ab51
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
@@ -0,0 +1,58 @@
+/*
+ * 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.fragment.cts;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class StrictViewFragment extends StrictFragment {
+ boolean mOnCreateViewCalled, mOnViewCreatedCalled, mOnDestroyViewCalled;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ checkGetActivity();
+ checkState("onCreateView", CREATED);
+ final View result = inflater.inflate(R.layout.strict_view_fragment, container, false);
+ mOnCreateViewCalled = true;
+ return result;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ if (view == null) {
+ throw new IllegalArgumentException("onViewCreated view argument should not be null");
+ }
+ checkGetActivity();
+ checkState("onViewCreated", CREATED);
+ mOnViewCreatedCalled = true;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (getView() == null) {
+ throw new IllegalStateException("getView returned null in onDestroyView");
+ }
+ checkGetActivity();
+ checkState("onDestroyView", CREATED);
+ mOnDestroyViewCalled = true;
+ }
+}
diff --git a/tests/sample/AndroidManifest.xml b/tests/sample/AndroidManifest.xml
index 2f32e86..b27e0d3 100755
--- a/tests/sample/AndroidManifest.xml
+++ b/tests/sample/AndroidManifest.xml
@@ -19,6 +19,7 @@
package="android.sample.cts">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.sample.SampleDeviceActivity" >
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index ae790fb..86bc616 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -14,6 +14,12 @@
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
new file mode 100644
index 0000000..515dc01
--- /dev/null
+++ b/tests/sample/DynamicConfig.xml
@@ -0,0 +1,32 @@
+<?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
new file mode 100644
index 0000000..8985bd6
--- /dev/null
+++ b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.sample.cts;
+
+import android.sample.SampleDeviceActivity;
+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;
+
+/**
+ * A simple compatibility test which includes results in the report.
+ *
+ * This class has 3 dummy tests that create report logs and log dummy metrics.
+ */
+public class SampleDeviceReportLogTest
+ 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;
+ private static final int MULTIPLICATION_NUMBER_2 = 97;
+ private static final int MULTIPLICATION_RESULT = 2231;
+ 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";
+
+ /**
+ * Constructor which passes the class of the activity to be instrumented.
+ */
+ public SampleDeviceReportLogTest() {
+ super(SampleDeviceActivity.class);
+ }
+
+ /**
+ * Sample test that creates and logs test metrics into a report log.
+ */
+ public void testMultiplication() {
+ // Perform test.
+ int product = MULTIPLICATION_NUMBER_1 * MULTIPLICATION_NUMBER_2;
+ assertTrue("Multiplication result do not match", product == MULTIPLICATION_RESULT);
+
+ // Log metrics from the test.
+ String reportLogName = getReportLogName();
+ String streamName = getStreamName("testMultiplication-stream-name");
+ DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
+ reportLog.addValue(EXPECTED_PRODUCT_TAG, 1.0 * MULTIPLICATION_RESULT, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ reportLog.addValue(ACTUAL_PRODUCT_TAG, 1.0 * product, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.setSummary(ACTUAL_PRODUCT_TAG, 1.0 * product, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit(getInstrumentation());
+ }
+
+ /**
+ * Sample test to check counting up.
+ */
+ public void testCountUp() {
+ String streamName = getStreamName("testCountUp-stream-name");
+ countHelper(1, streamName);
+ }
+
+ /**
+ * Sample test to check counting down.
+ */
+ public void testCountDown() {
+ String streamName = getStreamName("testCountDown-stream-name");
+ countHelper(2, streamName);
+ }
+
+ /**
+ * Sample test function that counts up or down based on test parameter. It creates and logs test
+ * metrics into a report log.
+ * @param testParameter {@link String} parameter passed by caller test function.
+ * @param streamName {@link String} name of the report log stream retrieved from dynamic config.
+ */
+ private void countHelper(int testParameter, String streamName) {
+ // Perform test.
+ int start;
+ int end;
+ if (testParameter == 1) {
+ start = COUNT_START;
+ end = COUNT_END;
+ for (int i = start; i <= end;) {
+ i++;
+ }
+ } else {
+ start = COUNT_END;
+ end = COUNT_START;
+ for (int i = start; i >= end;) {
+ i--;
+ }
+ }
+
+ // Log metrics.
+ String reportLogName = getReportLogName();
+ 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.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 7bd434e..2f6ce78 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
@@ -19,6 +19,7 @@
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;
@@ -36,6 +37,16 @@
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;
@@ -53,6 +64,43 @@
}
/**
+ * Measures the time taken to sort an array.
+ */
+ public void testSort() throws Exception {
+ // MeasureTime runs the workload N times and records the time taken by each run.
+ double[] result = MeasureTime.measure(REPEAT, new MeasureRun() {
+ /**
+ * The size of the array to sort.
+ */
+ private static final int ARRAY_SIZE = 100000;
+ private int[] array;
+ @Override
+ public void prepare(int i) throws Exception {
+ array = createArray(ARRAY_SIZE);
+ }
+ @Override
+ public void run(int i) throws Exception {
+ Arrays.sort(array);
+ assertTrue("Array not sorted", isSorted(array));
+ }
+ });
+ // 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");
+ 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);
+ // Every report must have a summary,
+ reportLog.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+ // Submit the report to the given instrumentation.
+ reportLog.submit(getInstrumentation());
+ }
+
+ /**
* Creates an array filled with random numbers of the given size.
*/
private static int[] createArray(int size) {
@@ -77,38 +125,37 @@
}
/**
- * Measures the time taken to sort an array.
+ * Retreives name of report log from dynamic config.
+ *
+ * @return {@link String} name of the report log.
*/
- public void testSort() throws Exception {
- // MeasureTime runs the workload N times and records the time taken by each run.
- double[] result = MeasureTime.measure(REPEAT, new MeasureRun() {
- /**
- * The size of the array to sort.
- */
- private static final int ARRAY_SIZE = 100000;
- private int[] array;
- @Override
- public void prepare(int i) throws Exception {
- array = createArray(ARRAY_SIZE);
- }
- @Override
- public void run(int i) throws Exception {
- Arrays.sort(array);
- assertTrue("Array not sorted", isSorted(array));
- }
- });
- // Compute the stats.
- Stat.StatResult stat = Stat.getStat(result);
- // Create a new report to hold the metrics.
- DeviceReportLog reportLog = new DeviceReportLog();
- // 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);
- // Every report must have a summary,
- reportLog.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
- // Submit the report to the given instrumentation.
- reportLog.submit(getInstrumentation());
+ 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/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index e39e18a..2e13650 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -462,7 +462,7 @@
* @param apiMethod the method read from the api file.
* @param reflectedMethod the method found via reflections.
*/
- private boolean areMethodModifiedCompatibile(JDiffMethod apiMethod ,
+ private boolean areMethodsModifiedCompatible(JDiffMethod apiMethod ,
Method reflectedMethod) {
// If the apiMethod isn't synchronized
@@ -479,7 +479,7 @@
int mod1 = reflectedMethod.getModifiers() & ~ignoredMods;
int mod2 = apiMethod.mModifier & ~ignoredMods;
- // We can ignore FINAL for final classes
+ // We can ignore FINAL for classes
if ((mModifier & Modifier.FINAL) != 0) {
mod1 &= ~Modifier.FINAL;
mod2 &= ~Modifier.FINAL;
@@ -495,10 +495,6 @@
private void checkMethodCompliance() {
for (JDiffMethod method : jDiffMethods) {
try {
- // this is because jdiff think a method in an interface is not abstract
- if (JDiffType.INTERFACE.equals(mClassType)) {
- method.mModifier |= Modifier.ABSTRACT;
- }
Method m = findMatchingMethod(method);
if (m == null) {
@@ -522,7 +518,7 @@
return;
}
- if (!areMethodModifiedCompatibile(method, m)) {
+ if (!areMethodsModifiedCompatible(method, m)) {
mResultObserver.notifyFailure(FailureType.MISMATCH_METHOD,
method.toReadableString(mAbsoluteClassName),
"Non-compatible method found when looking for " +
@@ -545,35 +541,62 @@
* @param method the reflected method to compare
* @return true, if both methods are the same
*/
- private boolean matches(JDiffMethod jDiffMethod, Method method) {
+ private boolean matches(JDiffMethod jDiffMethod, Method reflectedMethod) {
// If the method names aren't equal, the methods can't match.
- if (jDiffMethod.mName.equals(method.getName())) {
- String jdiffReturnType = jDiffMethod.mReturnType;
- String reflectionReturnType = typeToString(method.getGenericReturnType());
- List<String> jdiffParamList = jDiffMethod.mParamList;
-
- // Next, compare the return types of the two methods. If
- // they aren't equal, the methods can't match.
- if (jdiffReturnType.equals(reflectionReturnType)) {
- Type[] params = method.getGenericParameterTypes();
- // Next, check the method parameters. If they have
- // different number of parameters, the two methods
- // can't match.
- if (jdiffParamList.size() == params.length) {
- // If any of the parameters don't match, the
- // methods can't match.
- for (int i = 0; i < jdiffParamList.size(); i++) {
- if (!compareParam(jdiffParamList.get(i), params[i])) {
- return false;
- }
- }
- // We've passed all the tests, the methods do
- // match.
- return true;
- }
- }
+ if (!jDiffMethod.mName.equals(reflectedMethod.getName())) {
+ return false;
}
- return false;
+ String jdiffReturnType = jDiffMethod.mReturnType;
+ String reflectionReturnType = typeToString(reflectedMethod.getGenericReturnType());
+ List<String> jdiffParamList = jDiffMethod.mParamList;
+
+ // Next, compare the return types of the two methods. If
+ // they aren't equal, the methods can't match.
+ if (!jdiffReturnType.equals(reflectionReturnType)) {
+ return false;
+ }
+
+ Type[] params = reflectedMethod.getGenericParameterTypes();
+
+ // Next, check the method parameters. If they have different
+ // parameter lengths, the two methods can't match.
+ if (jdiffParamList.size() != params.length) {
+ return false;
+ }
+
+ boolean piecewiseParamsMatch = true;
+
+ // Compare method parameters piecewise and return true if they all match.
+ for (int i = 0; i < jdiffParamList.size(); i++) {
+ piecewiseParamsMatch &= compareParam(jdiffParamList.get(i), params[i]);
+ }
+ if (piecewiseParamsMatch) {
+ return true;
+ }
+
+ /** NOTE: There are cases where piecewise method parameter checking
+ * fails even though the strings are equal, so compare entire strings
+ * against each other. This is not done by default to avoid a
+ * TransactionTooLargeException.
+ * Additionally, this can fail anyway due to extra
+ * information dug up by reflection.
+ *
+ * TODO: fix parameter equality checking and reflection matching
+ * See https://b.corp.google.com/issues/27726349
+ */
+
+ StringBuilder reflectedMethodParams = new StringBuilder("");
+ StringBuilder jdiffMethodParams = new StringBuilder("");
+
+ for (int i = 0; i < jdiffParamList.size(); i++) {
+ jdiffMethodParams.append(jdiffParamList.get(i));
+ reflectedMethodParams.append(params[i]);
+ }
+
+ String jDiffFName = jdiffMethodParams.toString();
+ String refName = reflectedMethodParams.toString();
+
+ return jDiffFName.equals(refName);
}
/**
diff --git a/tests/tests/accounts/Android.mk b/tests/tests/accounts/Android.mk
index fccdb86..dc17e0e 100644
--- a/tests/tests/accounts/Android.mk
+++ b/tests/tests/accounts/Android.mk
@@ -21,7 +21,8 @@
# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := CtsAccountTestsCommon ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ CtsAccountTestsCommon ctstestrunner platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index dd1f51a..3520d9c 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -32,6 +32,7 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.StrictMode;
+import android.platform.test.annotations.Presubmit;
import android.test.ActivityInstrumentationTestCase2;
import java.io.IOException;
@@ -1440,6 +1441,7 @@
/**
* Test confirmCredentials()
*/
+ @Presubmit
public void testConfirmCredentials() throws IOException, AuthenticatorException,
OperationCanceledException {
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
index 0163a58..b57299f 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
@@ -15,9 +15,14 @@
*/
package android.animation.cts;
+import java.lang.Override;
+import java.lang.Runnable;
+import java.lang.Thread;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -55,15 +60,81 @@
}
public void testPlaySequentially() throws Throwable {
+ xAnimator.setRepeatCount(0);
+ yAnimator.setRepeatCount(0);
+ xAnimator.setDuration(50);
+ yAnimator.setDuration(50);
Animator[] animatorArray = {xAnimator, yAnimator};
-
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playSequentially(animatorArray);
+ verifySequentialPlayOrder(mAnimatorSet, animatorArray);
- assertFalse(mAnimatorSet.isRunning());
- startAnimation(mAnimatorSet);
- Thread.sleep(100);
- assertTrue(mAnimatorSet.isRunning());
+ ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 1f);
+ ValueAnimator anim2 = ValueAnimator.ofInt(0, 100);
+ anim1.setDuration(50);
+ anim2.setDuration(50);
+ AnimatorSet set = new AnimatorSet();
+ set.playSequentially(anim1, anim2);
+ verifySequentialPlayOrder(set, new Animator[] {anim1, anim2});
+ }
+
+ /**
+ * Start the animator, and verify the animators are played sequentially in the order that is
+ * defined in the array.
+ *
+ * @param set AnimatorSet to be started and verified
+ * @param animators animators that we put in the AnimatorSet, in the order that they'll play
+ */
+ private void verifySequentialPlayOrder(final AnimatorSet set, Animator[] animators)
+ throws Throwable {
+
+ final MyListener[] listeners = new MyListener[animators.length];
+ for (int i = 0; i < animators.length; i++) {
+ if (i == 0) {
+ listeners[i] = new MyListener();
+ } else {
+ final int current = i;
+ listeners[i] = new MyListener() {
+ @Override
+ public void onAnimationStart(Animator anim) {
+ super.onAnimationStart(anim);
+ // Check that the previous animator has finished.
+ assertTrue(listeners[current - 1].mEndIsCalled);
+ }
+ };
+ }
+ animators[i].addListener(listeners[i]);
+ }
+
+ final CountDownLatch startLatch = new CountDownLatch(1);
+ final CountDownLatch endLatch = new CountDownLatch(1);
+
+ set.addListener(new MyListener() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ endLatch.countDown();
+ }
+ });
+
+ long totalDuration = set.getTotalDuration();
+ assertFalse(set.isRunning());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ set.start();
+ startLatch.countDown();
+ }
+ });
+
+ // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(...)
+ // will return immediately.
+ assertTrue(startLatch.await(100, TimeUnit.MILLISECONDS));
+ assertTrue(set.isRunning());
+ assertTrue(endLatch.await(totalDuration * 2, TimeUnit.MILLISECONDS));
+ // Check that all the animators have finished.
+ for (int i = 0; i < listeners.length; i++) {
+ assertTrue(listeners[i].mEndIsCalled);
+ }
}
public void testPlayTogether() throws Throwable {
@@ -74,10 +145,44 @@
mAnimatorSet.playTogether(animatorArray);
assertFalse(mAnimatorSet.isRunning());
+ assertFalse(xAnimator.isRunning());
+ assertFalse(yAnimator.isRunning());
startAnimation(mAnimatorSet);
Thread.sleep(100);
assertTrue(mAnimatorSet.isRunning());
- }
+ assertTrue(xAnimator.isRunning());
+ assertTrue(yAnimator.isRunning());
+
+ // Now assemble another animator set
+ ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 100f);
+ ValueAnimator anim2 = ValueAnimator.ofFloat(10f, 100f);
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(anim1, anim2);
+
+ assertFalse(set.isRunning());
+ assertFalse(anim1.isRunning());
+ assertFalse(anim2.isRunning());
+ startAnimation(set);
+ Thread.sleep(100);
+ assertTrue(set.isRunning());
+ assertTrue(anim1.isRunning());
+ assertTrue(anim2.isRunning());
+ }
+
+ public void testPlayBeforeAfter() throws Throwable {
+ xAnimator.setRepeatCount(0);
+ yAnimator.setRepeatCount(0);
+ final ValueAnimator zAnimator = ValueAnimator.ofFloat(0f, 100f);
+
+ xAnimator.setDuration(50);
+ yAnimator.setDuration(50);
+ zAnimator.setDuration(50);
+
+ AnimatorSet set = new AnimatorSet();
+ set.play(yAnimator).before(zAnimator).after(xAnimator);
+
+ verifySequentialPlayOrder(set, new Animator[] {xAnimator, yAnimator, zAnimator});
+ }
public void testDuration() throws Throwable {
xAnimator.setRepeatCount(ValueAnimator.INFINITE);
@@ -243,4 +348,17 @@
int x = 1;
int y = 2;
}
+
+ class MyListener extends AnimatorListenerAdapter {
+ boolean mStartIsCalled = false;
+ boolean mEndIsCalled = false;
+
+ public void onAnimationStart(Animator animation) {
+ mStartIsCalled = true;
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ mEndIsCalled = true;
+ }
+ }
}
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java
index 8947de0..0e413c9 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.app.SharedElementCallback;
-import android.app.usage.cts.R;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -59,6 +58,9 @@
public static final String ARRIVE_RETURN_TIME_READY = "arriveReturnTimeReady";
public static final String ARRIVE_RETURN_TIME = "arriveReturnTime";
+ public static final String ENTER_VISIBILITY = "enterVisibility";
+ public static final String RETURN_VISIBILITY = "returnVisibility";
+
private int mLayoutId;
private int mTest;
private ResultReceiver mResultReceiver;
@@ -67,6 +69,8 @@
public int resultCode = 0;
public Bundle result = new Bundle();
+ public final OptionalVisibility exitVisibility = new OptionalVisibility();
+ public final OptionalVisibility reenterVisibility = new OptionalVisibility();
public boolean mPauseOnRestart;
public boolean mQuickFinish;
@@ -76,12 +80,6 @@
public CountDownLatch returnLatch = new CountDownLatch(1);
public CountDownLatch reenterLatch = new CountDownLatch(1);
- public static final int EXIT_TRANSITION_INDEX = 0;
- public static final int ENTER_TRANSITION_INDEX = 1;
- public static final int RETURN_TRANSITION_INDEX = 2;
- public static final int REENTER_TRANSITION_INDEX = 3;
- public static final int sVisibility[] = new int[4];
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -109,11 +107,10 @@
getWindow().setSharedElementEnterTransition(new ChangeBounds().setDuration(DURATION));
getWindow().setSharedElementReturnTransition(new ChangeBounds().setDuration(DURATION));
- getWindow().setEnterTransition(createVisibilityTransition(true, ENTER_TRANSITION_INDEX));
- getWindow().setReturnTransition(createVisibilityTransition(true, RETURN_TRANSITION_INDEX));
- getWindow().setExitTransition(createVisibilityTransition(false, EXIT_TRANSITION_INDEX));
- getWindow().setReenterTransition(createVisibilityTransition(false,
- REENTER_TRANSITION_INDEX));
+ getWindow().setEnterTransition(createVisibilityTransition(true, ENTER_VISIBILITY));
+ getWindow().setReturnTransition(createVisibilityTransition(true, RETURN_VISIBILITY));
+ getWindow().setExitTransition(createVisibilityTransition(false, exitVisibility));
+ getWindow().setReenterTransition(createVisibilityTransition(false, reenterVisibility));
getWindow().getReenterTransition().addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
@@ -131,10 +128,17 @@
startTest();
}
- private Transition createVisibilityTransition(boolean isExplode, int startIndex) {
+ private Transition createVisibilityTransition(boolean isExplode, OptionalVisibility visibility) {
final Transition transition = isExplode ? new Explode() : new Fade();
transition.setDuration(DURATION);
- transition.addListener(new VisibilityCheck(R.id.redSquare, startIndex));
+ transition.addListener(new VisibilityCheck(R.id.redSquare, visibility));
+ return transition;
+ }
+
+ private Transition createVisibilityTransition(boolean isExplode, String propertyName) {
+ final Transition transition = isExplode ? new Explode() : new Fade();
+ transition.setDuration(DURATION);
+ transition.addListener(new VisibilityCheck(R.id.redSquare, propertyName));
return transition;
}
@@ -237,17 +241,49 @@
private class VisibilityCheck extends TransitionListenerAdapter {
private final int mViewId;
- private final int mStartIndex;
+ private final OptionalVisibility mVisibility;
+ private final String mPropertyName;
- public VisibilityCheck(int viewId, int startIndex) {
+ public VisibilityCheck(int viewId, OptionalVisibility visibility) {
mViewId = viewId;
- this.mStartIndex = startIndex;
+ mVisibility = visibility;
+ mPropertyName = null;
+ }
+
+ public VisibilityCheck(int viewId, String propertyName) {
+ mViewId = viewId;
+ mVisibility = null;
+ mPropertyName = propertyName;
}
@Override
public void onTransitionEnd(Transition transition) {
final View view = findViewById(mViewId);
- sVisibility[mStartIndex ] = view.getVisibility();
+ if (mPropertyName != null) {
+ if (mResultReceiver != null) {
+ Bundle data = new Bundle();
+ data.putInt(mPropertyName, view.getVisibility());
+ mResultReceiver.send(RESULT_OK, data);
+ }
+ } else {
+ mVisibility.set(view.getVisibility());
+ }
+ }
+ }
+
+ public static class OptionalVisibility {
+ private int mVisibility = -1;
+
+ public void set(int visibility) {
+ mVisibility = visibility;
+ }
+
+ public int get() {
+ return mVisibility;
+ }
+
+ public boolean isSet() {
+ return mVisibility != -1;
}
}
}
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java
index b23edb7..25d885a 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java
@@ -17,7 +17,6 @@
import android.app.ActivityOptions;
import android.app.SharedElementCallback;
-import android.app.usage.cts.R;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -28,7 +27,6 @@
import android.transition.Transition.TransitionListener;
import android.view.View;
-import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -51,7 +49,6 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- Arrays.fill(ActivityTransitionActivity.sVisibility, -1);
setActivityInitialTouchMode(false);
mActivity = getActivity();
mNumArrivedCalls = 0;
@@ -135,12 +132,14 @@
runTestOnUiThread(new Runnable() {
@Override
public void run() {
+ mReceiver = new PassInfo(new Handler());
mActivity.mPauseOnRestart = true;
Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
mActivity.findViewById(R.id.hello), "target").toBundle();
Intent intent = new Intent(mActivity, ActivityTransitionActivity.class);
intent.putExtra(ActivityTransitionActivity.LAYOUT_ID, R.layout.end);
intent.putExtra(ActivityTransitionActivity.QUICK_FINISH, true);
+ intent.putExtra(ActivityTransitionActivity.RESULT_RECEIVER, mReceiver);
mActivity.startActivityForResult(intent, 0, options);
}
});
@@ -151,7 +150,7 @@
assertTrue("Reenter transition didn't finish", latch.await(1000, TimeUnit.MILLISECONDS));
assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
getInstrumentation().waitForIdleSync();
- checkNormalTransitionVisibility();
+ checkNoReturnTransitionVisibility();
runTestOnUiThread(new Runnable() {
@Override
public void run() {
@@ -168,12 +167,14 @@
runTestOnUiThread(new Runnable() {
@Override
public void run() {
+ mReceiver = new PassInfo(new Handler());
Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
mActivity.findViewById(R.id.hello), "target").toBundle();
Intent intent = new Intent(mActivity, ActivityTransitionActivity.class);
intent.putExtra(ActivityTransitionActivity.LAYOUT_ID, R.layout.end);
intent.putExtra(ActivityTransitionActivity.QUICK_FINISH, true);
intent.putExtra(ActivityTransitionActivity.ALLOW_OVERLAP, false);
+ intent.putExtra(ActivityTransitionActivity.RESULT_RECEIVER, mReceiver);
mActivity.startActivityForResult(intent, 0, options);
}
});
@@ -182,7 +183,7 @@
mActivity.returnLatch.await(1500, TimeUnit.MILLISECONDS));
assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
getInstrumentation().waitForIdleSync();
- checkNormalTransitionVisibility();
+ checkNoReturnTransitionVisibility();
runTestOnUiThread(new Runnable() {
@Override
public void run() {
@@ -200,12 +201,14 @@
runTestOnUiThread(new Runnable() {
@Override
public void run() {
+ mReceiver = new PassInfo(new Handler());
Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
mActivity.findViewById(R.id.hello), "target").toBundle();
Intent intent = new Intent(mActivity, ActivityTransitionActivity.class);
intent.putExtra(ActivityTransitionActivity.LAYOUT_ID, R.layout.end);
intent.putExtra(ActivityTransitionActivity.QUICK_FINISH, true);
intent.putExtra(ActivityTransitionActivity.ALLOW_OVERLAP, true);
+ intent.putExtra(ActivityTransitionActivity.RESULT_RECEIVER, mReceiver);
mActivity.startActivityForResult(intent, 0, options);
}
});
@@ -215,7 +218,7 @@
assertTrue("Reenter transition didn't finish", latch.await(1000, TimeUnit.MILLISECONDS));
assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
getInstrumentation().waitForIdleSync();
- checkNormalTransitionVisibility();
+ checkNoReturnTransitionVisibility();
runTestOnUiThread(new Runnable() {
@Override
public void run() {
@@ -232,6 +235,7 @@
runTestOnUiThread(new Runnable() {
@Override
public void run() {
+ mReceiver = new PassInfo(new Handler());
Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
mActivity.findViewById(R.id.hello), "target").toBundle();
Intent intent = new Intent(mActivity, ActivityTransitionActivity.class);
@@ -239,6 +243,7 @@
intent.putExtra(ActivityTransitionActivity.QUICK_FINISH, true);
intent.putExtra(ActivityTransitionActivity.ALLOW_OVERLAP, true);
intent.putExtra(ActivityTransitionActivity.NO_RETURN_TRANSITION, true);
+ intent.putExtra(ActivityTransitionActivity.RESULT_RECEIVER, mReceiver);
mActivity.startActivityForResult(intent, 0, options);
}
});
@@ -261,19 +266,18 @@
private void checkNormalTransitionVisibility() {
checkNoReturnTransitionVisibility();
- final int[] visibilities = ActivityTransitionActivity.sVisibility;
assertEquals(View.INVISIBLE,
- visibilities[ActivityTransitionActivity.RETURN_TRANSITION_INDEX]);
+ mReceiver.resultData.getInt(ActivityTransitionActivity.RETURN_VISIBILITY, -1));
}
private void checkNoReturnTransitionVisibility() {
- final int[] visibilities = ActivityTransitionActivity.sVisibility;
+ assertTrue(mActivity.exitVisibility.isSet());
+ assertTrue(mActivity.reenterVisibility.isSet());
+
assertEquals(View.VISIBLE,
- visibilities[ActivityTransitionActivity.ENTER_TRANSITION_INDEX]);
- assertEquals(View.INVISIBLE,
- visibilities[ActivityTransitionActivity.EXIT_TRANSITION_INDEX]);
- assertEquals(View.VISIBLE,
- visibilities[ActivityTransitionActivity.REENTER_TRANSITION_INDEX]);
+ mReceiver.resultData.getInt(ActivityTransitionActivity.ENTER_VISIBILITY, -1));
+ assertEquals(View.INVISIBLE, mActivity.exitVisibility.get());
+ assertEquals(View.VISIBLE, mActivity.reenterVisibility.get());
}
private CountDownLatch setReenterLatch() {
@@ -303,9 +307,10 @@
mActivity.getWindow().getReenterTransition().addListener(listener);
return latch;
}
+
public static class PassInfo extends ResultReceiver {
public int resultCode;
- public Bundle resultData;
+ public Bundle resultData = new Bundle();
public PassInfo(Handler handler) {
super(handler);
@@ -314,7 +319,9 @@
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
this.resultCode = resultCode;
- this.resultData = resultData;
+ if (resultData != null) {
+ this.resultData.putAll(resultData);
+ }
}
}
}
diff --git a/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java b/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
index 5b0e0c7..695a138 100644
--- a/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
+++ b/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
@@ -19,9 +19,11 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
+import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.util.Log;
@@ -53,6 +55,7 @@
private static final String LOCAL_BACKUP_COMPONENT =
"android/com.android.internal.backup.LocalTransport";
private static final String CALLLOG_BACKUP_PACKAGE = "com.android.providers.calllogbackup";
+ private static final String ALT_CALLLOG_BACKUP_PACKAGE = "com.android.calllogbackup";
private static final String TEST_NUMBER = "555-1234";
private static final int CALL_START_TIME = 0;
@@ -88,9 +91,18 @@
int presentation;
}
+ private String mCallLogBackupPackageName;
+
@Override
protected void setUp() throws Exception {
super.setUp();
+ PackageManager pm = getContext().getPackageManager();
+ try {
+ pm.getPackageInfo(CALLLOG_BACKUP_PACKAGE, 0);
+ mCallLogBackupPackageName = CALLLOG_BACKUP_PACKAGE;
+ } catch (PackageManager.NameNotFoundException e) {
+ mCallLogBackupPackageName = ALT_CALLLOG_BACKUP_PACKAGE;
+ }
}
/**
@@ -103,16 +115,23 @@
* 6) Verify that we the call from step (2)
*/
public void testSingleCallBackup() throws Exception {
+ if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ Log.i(TAG, "Skipping calllog tests: no telephony feature");
+ return;
+ }
// This CTS test depends on the local transport and so if it is not present,
// skip the test with success.
if (!hasBackupTransport(LOCAL_BACKUP_COMPONENT)) {
- Log.i(TAG, "skipping calllog tests");
+ Log.i(TAG, "skipping calllog tests: no local transport");
return;
}
// Turn on backup and set to the local backup agent.
boolean previouslyEnabled = enableBackup(true /* enable */);
String oldTransport = setBackupTransport(LOCAL_BACKUP_COMPONENT);
+ int previousFullDataBackupAware = Settings.Secure.getInt(getContext().getContentResolver(),
+ "user_full_data_backup_aware", 0);
+ enableFullDataBackupAware(1);
// Clear the call log
Log.i(TAG, "Clearing the call log");
@@ -125,7 +144,7 @@
// Run backup for the call log (saves the single call).
Log.i(TAG, "Running backup");
- runBackupFor(CALLLOG_BACKUP_PACKAGE);
+ runBackupFor(mCallLogBackupPackageName);
Thread.sleep(TIMEOUT_BACKUP); // time for backup
// Clear the call log and verify that it is empty
@@ -135,7 +154,7 @@
// Restore from the previous backup and verify we have the new call again.
Log.i(TAG, "Restoring the single call");
- runRestoreFor(CALLLOG_BACKUP_PACKAGE);
+ runRestoreFor(mCallLogBackupPackageName);
Thread.sleep(TIMEOUT_BACKUP); // time for restore
verifyCall();
@@ -144,6 +163,7 @@
Log.i(TAG, "Reseting backup");
setBackupTransport(oldTransport);
enableBackup(previouslyEnabled);
+ enableFullDataBackupAware(previousFullDataBackupAware);
}
private Call verifyCall() {
@@ -183,6 +203,10 @@
exec("bmgr restore " + packageName);
}
+ private void enableFullDataBackupAware(int status) throws Exception {
+ exec("settings put secure user_full_data_backup_aware " + status);
+ }
+
private String setBackupTransport(String transport) throws Exception {
String output = exec("bmgr transport " + transport);
Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
diff --git a/tests/tests/automotive/Android.mk b/tests/tests/car/Android.mk
similarity index 95%
rename from tests/tests/automotive/Android.mk
rename to tests/tests/car/Android.mk
index abef2ac..0138317 100644
--- a/tests/tests/automotive/Android.mk
+++ b/tests/tests/car/Android.mk
@@ -16,7 +16,7 @@
include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsAutomotiveTestCases
+LOCAL_PACKAGE_NAME := CtsCarTestCases
# Don't include this package in any target.
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/automotive/AndroidManifest.xml b/tests/tests/car/AndroidManifest.xml
similarity index 100%
rename from tests/tests/automotive/AndroidManifest.xml
rename to tests/tests/car/AndroidManifest.xml
diff --git a/tests/tests/automotive/AndroidTest.xml b/tests/tests/car/AndroidTest.xml
similarity index 87%
rename from tests/tests/automotive/AndroidTest.xml
rename to tests/tests/car/AndroidTest.xml
index b4af1f5..d82c101 100644
--- a/tests/tests/automotive/AndroidTest.xml
+++ b/tests/tests/car/AndroidTest.xml
@@ -16,9 +16,9 @@
<configuration description="Config for CTS Automotive test cases">
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsAutomotiveTestCases.apk" />
+ <option name="test-file-name" value="CtsCarTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.support.car.cts" />
+ <option name="package" value="android.car.cts" />
</test>
</configuration>
diff --git a/tests/tests/automotive/src/android/car/cts/CarApiTestBase.java b/tests/tests/car/src/android/car/cts/CarApiTestBase.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/CarApiTestBase.java
rename to tests/tests/car/src/android/car/cts/CarApiTestBase.java
diff --git a/tests/tests/automotive/src/android/car/cts/CarAppContextManagerTest.java b/tests/tests/car/src/android/car/cts/CarAppContextManagerTest.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/CarAppContextManagerTest.java
rename to tests/tests/car/src/android/car/cts/CarAppContextManagerTest.java
diff --git a/tests/tests/car/src/android/car/cts/CarAudioManagerTest.java b/tests/tests/car/src/android/car/cts/CarAudioManagerTest.java
new file mode 100644
index 0000000..cec1db6
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarAudioManagerTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.car.cts;
+
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.media.AudioAttributes;
+
+/** Unit tests for {@link CarAudioManager}. */
+public class CarAudioManagerTest extends CarApiTestBase {
+ private static final String TAG = CarAudioManagerTest.class.getSimpleName();
+ private CarAudioManager mManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE);
+ assertNotNull(mManager);
+ }
+
+ public void testGetAudioAttributesForCarUsageForMusic() throws Exception {
+ AudioAttributes.Builder musicBuilder = new AudioAttributes.Builder();
+ musicBuilder.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+ .setUsage(AudioAttributes.USAGE_MEDIA);
+
+ assertEquals(musicBuilder.build(), mManager.getAudioAttributesForCarUsage(
+ CarAudioManager.CAR_AUDIO_USAGE_MUSIC));
+ }
+
+ public void testGetAudioAttributesForCarUsageForUnknown() throws Exception {
+ AudioAttributes.Builder unknownBuilder = new AudioAttributes.Builder();
+ unknownBuilder.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+ .setUsage(AudioAttributes.USAGE_UNKNOWN);
+
+ assertEquals(unknownBuilder.build(), mManager.getAudioAttributesForCarUsage(10007));
+ }
+}
diff --git a/tests/tests/automotive/src/android/car/cts/CarInfoManagerTest.java b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/CarInfoManagerTest.java
rename to tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
diff --git a/tests/tests/automotive/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
similarity index 60%
rename from tests/tests/automotive/src/android/car/cts/CarPackageManagerTest.java
rename to tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index 2865710..dc5fe0a 100644
--- a/tests/tests/automotive/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -18,16 +18,21 @@
import android.car.Car;
import android.car.CarNotConnectedException;
import android.car.content.pm.CarPackageManager;
-import android.telecom.TelecomManager;
-import android.util.Log;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
-import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.ExecutionException;
public class CarPackageManagerTest extends CarApiTestBase {
private CarPackageManager mCarPm;
+ private static String TAG = CarPackageManagerTest.class.getSimpleName();
+
+ /** Name of the meta-data attribute for the automotive application XML resource */
+ private static final String METADATA_ATTRIBUTE = "android.car.application";
+
@Override
protected void setUp() throws Exception {
@@ -39,8 +44,6 @@
assertFalse(mCarPm.isActivityAllowedWhileDriving("com.basic.package", "DummyActivity"));
// Real system activity is not allowed as well.
assertFalse(mCarPm.isActivityAllowedWhileDriving("com.android.phone", "CallActivity"));
- assertTrue(mCarPm.isActivityAllowedWhileDriving(
- "com.google.android.car.media", "com.google.android.car.media.MediaProxyActivity"));
try {
mCarPm.isActivityAllowedWhileDriving("com.android.settings", null);
@@ -62,6 +65,32 @@
}
}
+ public void testSystemActivitiesAllowed() throws CarNotConnectedException {
+ List<PackageInfo> packages = getContext().getPackageManager().getInstalledPackages(
+ PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+
+ for (PackageInfo info : packages) {
+ if (info.applicationInfo == null) {
+ continue;
+ }
+ if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ||
+ ((info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
+
+ Bundle metaData = info.applicationInfo.metaData;
+ if (metaData == null || metaData.getInt(METADATA_ATTRIBUTE, 0) == 0) {
+ continue; // No car metadata, ignoring this app.
+ }
+
+ if (info.activities != null && info.activities.length > 0) {
+ String activity = info.activities[0].name;
+ String packageName = info.packageName;
+ assertTrue("Failed for package: " + packageName + ", activity: " + activity,
+ mCarPm.isActivityAllowedWhileDriving(packageName, activity));
+ }
+ }
+ }
+ }
+
public void testServiceAllowedWhileDriving() throws Exception {
assertFalse(mCarPm.isServiceAllowedWhileDriving("com.basic.package", ""));
assertTrue(mCarPm.isServiceAllowedWhileDriving("com.android.settings", "Any"));
@@ -75,4 +104,5 @@
// Expected.
}
}
+
}
diff --git a/tests/tests/automotive/src/android/car/cts/CarSensorManagerTest.java b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/CarSensorManagerTest.java
rename to tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
diff --git a/tests/tests/automotive/src/android/car/cts/CarTest.java b/tests/tests/car/src/android/car/cts/CarTest.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/CarTest.java
rename to tests/tests/car/src/android/car/cts/CarTest.java
diff --git a/tests/tests/automotive/src/android/car/cts/CarUiProviderTest.java b/tests/tests/car/src/android/car/cts/CarUiProviderTest.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/CarUiProviderTest.java
rename to tests/tests/car/src/android/car/cts/CarUiProviderTest.java
diff --git a/tests/tests/automotive/src/android/car/cts/ExceptionsTest.java b/tests/tests/car/src/android/car/cts/ExceptionsTest.java
similarity index 100%
rename from tests/tests/automotive/src/android/car/cts/ExceptionsTest.java
rename to tests/tests/car/src/android/car/cts/ExceptionsTest.java
diff --git a/tests/tests/content/AndroidManifest.xml b/tests/tests/content/AndroidManifest.xml
index d88fdad..d4f203e 100644
--- a/tests/tests/content/AndroidManifest.xml
+++ b/tests/tests/content/AndroidManifest.xml
@@ -21,7 +21,6 @@
<!-- content sync tests -->
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
diff --git a/tests/tests/content/res/color-land/testcolor_orientation.xml b/tests/tests/content/res/color-land/testcolor_orientation.xml
new file mode 100644
index 0000000..f9e285b
--- /dev/null
+++ b/tests/tests/content/res/color-land/testcolor_orientation.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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/white" />
+</selector>
diff --git a/tests/tests/content/res/drawable/testcolor.xml b/tests/tests/content/res/color/testcolor.xml
similarity index 100%
rename from tests/tests/content/res/drawable/testcolor.xml
rename to tests/tests/content/res/color/testcolor.xml
diff --git a/tests/tests/content/res/color/testcolor_orientation.xml b/tests/tests/content/res/color/testcolor_orientation.xml
new file mode 100644
index 0000000..bef1ef6
--- /dev/null
+++ b/tests/tests/content/res/color/testcolor_orientation.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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/black" />
+</selector>
diff --git a/tests/tests/content/res/color/testcolor_themed.xml b/tests/tests/content/res/color/testcolor_themed.xml
new file mode 100644
index 0000000..eee0526
--- /dev/null
+++ b/tests/tests/content/res/color/testcolor_themed.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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?attr/themeColor" />
+</selector>
diff --git a/tests/tests/content/res/drawable/colordrawable_themed.xml b/tests/tests/content/res/drawable/colordrawable_themed.xml
new file mode 100644
index 0000000..eacbe65
--- /dev/null
+++ b/tests/tests/content/res/drawable/colordrawable_themed.xml
@@ -0,0 +1,20 @@
+<?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.
+ */
+-->
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?attr/themeColor" />
diff --git a/tests/tests/content/res/values/attrs.xml b/tests/tests/content/res/values/attrs.xml
index ac88ef6..12b731b 100644
--- a/tests/tests/content/res/values/attrs.xml
+++ b/tests/tests/content/res/values/attrs.xml
@@ -48,6 +48,9 @@
<attr name="type14" format="string"/>
<attr name="type15" format="reference"/>
<attr name="type16" format="string"/>
+ <attr name="type17" format="reference|color"/>
+ <attr name="typeEmpty" format="reference"/>
+ <attr name="typeUndefined" format="reference"/>
<declare-styleable name="style1">
<attr name="type1"/>
<attr name="type2"/>
@@ -65,6 +68,9 @@
<attr name="type14"/>
<attr name="type15"/>
<attr name="type16"/>
+ <attr name="type17"/>
+ <attr name="typeEmpty"/>
+ <attr name="typeUndefined"/>
</declare-styleable>
<attr name="testEnum">
<enum name="val1" value="1" />
diff --git a/tests/tests/content/res/values/styles.xml b/tests/tests/content/res/values/styles.xml
index b27968d..c6e4b1d 100644
--- a/tests/tests/content/res/values/styles.xml
+++ b/tests/tests/content/res/values/styles.xml
@@ -33,6 +33,9 @@
<item name="type14">TypedArray Test!</item>
<item name="type15">@array/difficultyLevel</item>
<item name="type16">Typed Value!</item>
+ <item name="type17">@color/testcolor_orientation</item>
+ <item name="typeEmpty">@empty</item>
+ <item name="typeUndefined">@null</item>
</style>
<style name="TextViewWithoutColorAndAppearance">
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index c988f77..4cb85cc 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -16,10 +16,6 @@
package android.content.cts;
-import android.content.cts.R;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.Context;
import android.content.cts.util.XmlUtils;
import android.content.res.ColorStateList;
@@ -34,6 +30,8 @@
import android.util.Xml;
import android.view.WindowManager;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.File;
import java.io.IOException;
@@ -90,11 +88,11 @@
* they don't have file-based encryption, so that apps can go through a
* backup/restore cycle between FBE and non-FBE devices.
*/
- public void testCreateDeviceEncryptedStorageContext() throws Exception {
- final Context deviceContext = mContext.createDeviceEncryptedStorageContext();
+ public void testCreateDeviceProtectedStorageContext() throws Exception {
+ final Context deviceContext = mContext.createDeviceProtectedStorageContext();
- assertFalse(mContext.isDeviceEncryptedStorage());
- assertTrue(deviceContext.isDeviceEncryptedStorage());
+ assertFalse(mContext.isDeviceProtectedStorage());
+ assertTrue(deviceContext.isDeviceProtectedStorage());
final File defaultFile = new File(mContext.getFilesDir(), "test");
final File deviceFile = new File(deviceContext.getFilesDir(), "test");
@@ -108,21 +106,21 @@
assertTrue(deviceFile.exists());
}
- public void testMigrateSharedPreferencesFrom() throws Exception {
- final Context deviceContext = mContext.createDeviceEncryptedStorageContext();
+ public void testMoveSharedPreferencesFrom() throws Exception {
+ final Context deviceContext = mContext.createDeviceProtectedStorageContext();
mContext.getSharedPreferences("test", Context.MODE_PRIVATE).edit().putInt("answer", 42)
.commit();
// Verify that we can migrate
- assertTrue(deviceContext.migrateSharedPreferencesFrom(mContext, "test"));
+ assertTrue(deviceContext.moveSharedPreferencesFrom(mContext, "test"));
assertEquals(0, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(42, deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
// Trying to migrate again when already done is a no-op
- assertTrue(deviceContext.migrateSharedPreferencesFrom(mContext, "test"));
+ assertTrue(deviceContext.moveSharedPreferencesFrom(mContext, "test"));
assertEquals(0, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(42, deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE)
@@ -132,7 +130,7 @@
deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE).edit()
.putInt("question", 24).commit();
- assertTrue(mContext.migrateSharedPreferencesFrom(deviceContext, "test"));
+ assertTrue(mContext.moveSharedPreferencesFrom(deviceContext, "test"));
assertEquals(42, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(24, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
@@ -143,8 +141,8 @@
.getInt("question", 0));
}
- public void testMigrateDatabaseFrom() throws Exception {
- final Context deviceContext = mContext.createDeviceEncryptedStorageContext();
+ public void testMoveDatabaseFrom() throws Exception {
+ final Context deviceContext = mContext.createDeviceProtectedStorageContext();
SQLiteDatabase db = mContext.openOrCreateDatabase("test.db",
Context.MODE_PRIVATE | Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, null);
@@ -154,7 +152,7 @@
db.close();
// Verify that we can migrate
- assertTrue(deviceContext.migrateDatabaseFrom(mContext, "test.db"));
+ assertTrue(deviceContext.moveDatabaseFrom(mContext, "test.db"));
db = deviceContext.openOrCreateDatabase("test.db",
Context.MODE_PRIVATE | Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, null);
Cursor c = db.query("list", null, null, null, null, null, null);
@@ -168,10 +166,10 @@
db.close();
// Trying to migrate again when already done is a no-op
- assertTrue(deviceContext.migrateDatabaseFrom(mContext, "test.db"));
+ assertTrue(deviceContext.moveDatabaseFrom(mContext, "test.db"));
// Verify that we can migrate back
- assertTrue(mContext.migrateDatabaseFrom(deviceContext, "test.db"));
+ assertTrue(mContext.moveDatabaseFrom(deviceContext, "test.db"));
db = mContext.openOrCreateDatabase("test.db",
Context.MODE_PRIVATE | Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, null);
c = db.query("list", null, null, null, null, null, null);
diff --git a/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java b/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java
index e4a9500..f5dc5ca 100644
--- a/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java
+++ b/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java
@@ -24,9 +24,11 @@
import java.util.Arrays;
import android.content.res.AssetFileDescriptor;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
public class AssetFileDescriptorTest extends AndroidTestCase {
private static final long START_OFFSET = 0;
@@ -66,6 +68,31 @@
getContext().deleteFile(FILE_NAME);
}
+ @SmallTest
+ public void testConstructor() throws IOException {
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(
+ mFile, ParcelFileDescriptor.MODE_READ_WRITE);
+ AssetFileDescriptor assetFileDes;
+ Bundle extras;
+
+ assetFileDes = new AssetFileDescriptor(fd, START_OFFSET, LENGTH);
+ assertNotNull(assetFileDes);
+ assetFileDes.close();
+
+ extras = null;
+ assetFileDes = new AssetFileDescriptor(fd, START_OFFSET, LENGTH, extras);
+ assertEquals(extras, assetFileDes.getExtras());
+ assertNotNull(assetFileDes);
+ assetFileDes.close();
+
+ extras = new Bundle();
+ assetFileDes = new AssetFileDescriptor(fd, START_OFFSET, LENGTH, extras);
+ assertEquals(extras, assetFileDes.getExtras());
+ assertNotNull(assetFileDes);
+ assetFileDes.close();
+ }
+
+ @SmallTest
public void testInputOutputStream() throws IOException {
/*
* test createOutputStream() and createInputStrean()
@@ -150,6 +177,7 @@
}
}
+ @SmallTest
public void testMiscMethod() {
// test getLength()
assertEquals(LENGTH, mAssetFileDes.getLength());
diff --git a/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java b/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
index b861264..4893ec1 100644
--- a/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
+++ b/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
@@ -26,6 +26,7 @@
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.TypedValue;
import java.io.BufferedReader;
@@ -45,6 +46,7 @@
mAssets = mContext.getAssets();
}
+ @SmallTest
public void testAssetOperations() throws IOException, XmlPullParserException {
final Resources res = getContext().getResources();
final TypedValue value = new TypedValue();
@@ -117,7 +119,23 @@
}
+ @SmallTest
+ public void testClose() throws IOException, XmlPullParserException {
+ final AssetManager assets = new AssetManager();
+ assets.close();
+ // Should no-op.
+ assets.close();
+
+ try {
+ assets.openXmlResourceParser("AndroidManifest.xml");
+ fail("Expected RuntimeException");
+ } catch (RuntimeException e) {
+ // Expected.
+ }
+ }
+
+ @SmallTest
public void testGetNonSystemLocales() {
// This is the list of locales built into this test package. It is basically the locales
// specified in the Android.mk files (assuming they have corresponding resources), plus the
diff --git a/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java b/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java
index 2222ce4..2029b95 100644
--- a/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java
@@ -20,51 +20,110 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
import android.graphics.Color;
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.content.cts.R;
-
+import android.test.suitebuilder.annotation.SmallTest;
public class ColorStateListTest extends AndroidTestCase {
- public void testColorStateList() throws NotFoundException, XmlPullParserException, IOException {
- final int[][] state = new int[][] { { 0 }, { 0 } };
- final int[] colors = new int[] { Color.RED, Color.BLUE };
- ColorStateList c = new ColorStateList(state, colors);
+
+ @SmallTest
+ public void testConstructor() {
+ final int[][] state = new int[][]{{0}, {0}};
+ final int[] colors = new int[]{Color.RED, Color.BLUE};
+ final ColorStateList c = new ColorStateList(state, colors);
assertTrue(c.isStateful());
assertEquals(Color.RED, c.getDefaultColor());
+ }
- final int alpha = 36;
- final ColorStateList c1 = c.withAlpha(alpha);
- assertNotSame(Color.RED, c1.getDefaultColor());
- // check alpha
- assertEquals(alpha, c1.getDefaultColor() >>> 24);
- assertEquals(Color.RED & 0x00FF0000, c1.getDefaultColor() & 0x00FF0000);
-
- final int xmlId = R.drawable.testcolor;
- final int colorInXml = 0xFFA6C839;// this color value is define in testcolor.xml file.
+ @SmallTest
+ public void testCreateFromXml() throws Exception {
+ final int xmlId = R.color.testcolor;
+ final int colorInXml = 0xFFA6C839; // this color value is defined in testcolor.xml file.
final Resources res = getContext().getResources();
- c = ColorStateList.createFromXml(res, res.getXml(xmlId));
+ final ColorStateList c = ColorStateList.createFromXml(res, res.getXml(xmlId));
assertEquals(colorInXml, c.getDefaultColor());
assertEquals(0, c.describeContents());
assertFalse(c.isStateful());
assertNotNull(c.toString());
assertEquals(colorInXml, c.getColorForState(new int[]{0}, 0));
+ }
- c = ColorStateList.valueOf(Color.GRAY);
+ @SmallTest
+ public void testCreateFromXmlThemed() throws Exception {
+ final int xmlId = R.color.testcolor_themed;
+ final int colorInXml = Color.BLACK; // this color value is defined in styles.xml file.
+ final Resources res = getContext().getResources();
+ final Theme theme = res.newTheme();
+ theme.applyStyle(R.style.Theme_ThemedDrawableTest, true);
+ final ColorStateList c = ColorStateList.createFromXml(res, res.getXml(xmlId), theme);
+ assertEquals(colorInXml, c.getDefaultColor());
+ assertEquals(0, c.describeContents());
+ assertFalse(c.isStateful());
+ assertNotNull(c.toString());
+ assertEquals(colorInXml, c.getColorForState(new int[]{0}, 0));
+ }
+
+ @SmallTest
+ public void testGetChangingConfigurations() {
+ final Resources res = getContext().getResources();
+ ColorStateList c;
+
+ c = res.getColorStateList(R.color.testcolor, null);
+ assertEquals(c.getChangingConfigurations(), 0);
+
+ c = res.getColorStateList(R.color.testcolor_orientation, null);
+ assertEquals(ActivityInfo.CONFIG_ORIENTATION, c.getChangingConfigurations());
+ }
+
+ @SmallTest
+ public void testWithAlpha() {
+ final int[][] state = new int[][]{{0}, {0}};
+ final int[] colors = new int[]{Color.RED, Color.BLUE};
+ final ColorStateList c = new ColorStateList(state, colors);
+ final int alpha = 36;
+ final ColorStateList c1 = c.withAlpha(alpha);
+ assertNotSame(Color.RED, c1.getDefaultColor());
+ assertEquals(alpha, c1.getDefaultColor() >>> 24);
+ assertEquals(Color.RED & 0x00FF0000, c1.getDefaultColor() & 0x00FF0000);
+ }
+
+ @SmallTest
+ public void testValueOf() {
+ final ColorStateList c = ColorStateList.valueOf(Color.GRAY);
assertEquals(Color.GRAY, c.getDefaultColor());
+ }
+ @SmallTest
+ public void testParcelable() {
+ final ColorStateList c = ColorStateList.valueOf(Color.GRAY);
final Parcel parcel = Parcel.obtain();
c.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
- ColorStateList actual = ColorStateList.CREATOR.createFromParcel(parcel);
- // can only compare the state and the default color. because no API to
- // get every color of ColorStateList
+
+ final ColorStateList actual = ColorStateList.CREATOR.createFromParcel(parcel);
assertEquals(c.isStateful(), actual.isStateful());
assertEquals(c.getDefaultColor(), actual.getDefaultColor());
}
+
+ @SmallTest
+ public void testIsOpaque() {
+ ColorStateList c;
+
+ c = ColorStateList.valueOf(Color.GRAY);
+ assertTrue(c.isOpaque());
+
+ c = ColorStateList.valueOf(0x80FFFFFF);
+ assertFalse(c.isOpaque());
+
+ c = ColorStateList.valueOf(Color.TRANSPARENT);
+ assertFalse(c.isOpaque());
+ }
}
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
index c1ee6c4..bc0f42e 100644
--- a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
@@ -403,6 +403,14 @@
assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
}
+ public void testIsScreenRound() {
+ Configuration config = new Configuration();
+ assertFalse(config.isScreenRound());
+
+ config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+ assertTrue(config.isScreenRound());
+ }
+
public void testFixUpLocaleList() {
Configuration config = new Configuration();
diff --git a/tests/tests/content/src/android/content/res/cts/Resources_NotFoundExceptionTest.java b/tests/tests/content/src/android/content/res/cts/Resources_NotFoundExceptionTest.java
index 8fa8d7b..d75fcdd 100644
--- a/tests/tests/content/src/android/content/res/cts/Resources_NotFoundExceptionTest.java
+++ b/tests/tests/content/src/android/content/res/cts/Resources_NotFoundExceptionTest.java
@@ -23,41 +23,57 @@
public class Resources_NotFoundExceptionTest extends TestCase {
public void testNotFoundException() {
- NotFoundException ne = null;
- boolean isThrowed = false;
- boolean isFinnalyRun = false;
+ NotFoundException ne;
+ boolean wasThrown;
+
+ wasThrown = false;
+ ne = new NotFoundException();
+
try {
- ne = new NotFoundException();
throw ne;
} catch (NotFoundException e) {
// expected
assertSame(ne, e);
- isThrowed = true;
+ wasThrown = true;
} finally {
- if (!isThrowed) {
+ if (!wasThrown) {
fail("should throw out NotFoundException");
}
- isFinnalyRun = true;
}
- assertTrue(isFinnalyRun);
- isThrowed = false;
- isFinnalyRun = false;
final String MESSAGE = "test";
+ wasThrown = false;
+ ne = new NotFoundException(MESSAGE);
+
try {
- ne = new NotFoundException(MESSAGE);
throw ne;
} catch (NotFoundException e) {
// expected
assertSame(ne, e);
assertEquals(MESSAGE, e.getMessage());
- isThrowed = true;
+ wasThrown = true;
} finally {
- if (!isThrowed) {
+ if (!wasThrown) {
fail("should throw out NotFoundException");
}
- isFinnalyRun = true;
}
- assertTrue(isFinnalyRun);
+
+ final Exception CAUSE = new NullPointerException();
+ wasThrown = false;
+ ne = new NotFoundException(MESSAGE, CAUSE);
+
+ try {
+ throw ne;
+ } catch (NotFoundException e) {
+ // expected
+ assertSame(ne, e);
+ assertEquals(MESSAGE, e.getMessage());
+ assertEquals(CAUSE, e.getCause());
+ wasThrown = true;
+ } finally {
+ if (!wasThrown) {
+ fail("should throw out NotFoundException");
+ }
+ }
}
}
diff --git a/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java b/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
index 533b186..b7a621f 100644
--- a/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
+++ b/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
@@ -23,7 +23,10 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.util.Xml;
@@ -44,6 +47,7 @@
mResTheme = getContext().getResources().newTheme();
}
+ @SmallTest
public void testSetMethods() {
// call a native method, and have no way to get the style
mResTheme.applyStyle(R.raw.testmp3, false);
@@ -54,6 +58,7 @@
mResTheme.setTo(other);
}
+ @SmallTest
public void testObtainStyledAttributes() {
final int[] attrs = new int[1];
attrs[0] = R.raw.testmp3;
@@ -77,12 +82,14 @@
testTypedArray.recycle();
}
+ @SmallTest
public void testResolveAttribute() {
final TypedValue value = new TypedValue();
getContext().getResources().getValue(R.raw.testmp3, value, true);
assertFalse(mResTheme.resolveAttribute(R.raw.testmp3, value, false));
}
+ @SmallTest
public void testGetChangingConfigurations() {
Resources.Theme theme = getContext().getResources().newTheme();
assertEquals("Initial changing configuration mask is empty",
@@ -104,6 +111,7 @@
theme.getChangingConfigurations());
}
+ @SmallTest
public void testRebase() {
Resources res = getContext().getResources();
Configuration config = res.getConfiguration();
@@ -132,4 +140,21 @@
assertEquals("Theme was rebased in RTL config", true, t.getBoolean(0, false));
t.recycle();
}
+
+ @SmallTest
+ public void testGetDrawable() {
+ final Resources res = getContext().getResources();
+ final Theme theme = res.newTheme();
+ theme.applyStyle(R.style.Theme_ThemedDrawableTest, true);
+
+ final ColorDrawable dr = (ColorDrawable) theme.getDrawable(R.drawable.colordrawable_themed);
+ assertEquals(Color.BLACK, dr.getColor());
+ }
+
+ @SmallTest
+ public void testGetResources() {
+ final Resources res = getContext().getResources();
+ final Theme theme = res.newTheme();
+ assertSame(res, theme.getResources());
+ }
}
diff --git a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
index 2eb82a8..ee7449c 100644
--- a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
+++ b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
@@ -16,11 +16,11 @@
package android.content.res.cts;
-import android.content.cts.R;
-
import org.xmlpull.v1.XmlPullParserException;
+import android.content.cts.R;
import android.content.cts.util.XmlUtils;
+import android.content.pm.ActivityInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.test.AndroidTestCase;
@@ -30,12 +30,10 @@
import java.io.IOException;
-
-public class TypedArrayTest extends AndroidTestCase{
- private TypedArray mTypedArray;
+public class TypedArrayTest extends AndroidTestCase {
private static final int DEFINT = -1;
private static final float DEFFLOAT = -1.0f;
- private static final int EXPECTEDCLOLOR = 0xff0000ff;
+ private static final int EXPECTED_COLOR = 0xff0000ff;
private static final int EXPECTED_COLOR_STATE = 0xff00ff00;
private static final float EXPECTED_DIMENSION = 0.75f;
private static final int EXPECTED_PIXEL_OFFSET = 10;
@@ -47,20 +45,23 @@
private static final String EXPECTED_STRING = "Hello, Android!";
private static final String EXPECTED_TEXT = "TypedArray Test!";
private static final String[] EXPECTED_TEXT_ARRAY = {"Easy", "Medium", "Hard"};
- private static final int EXPETED_INDEX = 15;
+ private static final int EXPECTED_INDEX = 15;
private static final TypedValue DEF_VALUE = new TypedValue();
- private static final int EXPECTED_INDEX_COUNT = 16;
+ private static final int EXPECTED_INDEX_COUNT = 17;
private static final String EXPTECTED_POS_DESCRIP = "<internal>";
- private static final int EXPECTED_LENGTH = 16;
+ private static final int EXPECTED_LENGTH = 19;
private static final String EXPECTED_NON_RESOURCE_STRING = "testNonResourcesString";
private static final String XML_BEGIN = "resources";
private static final int EXPECTED_INT_ATT = 86400;
+ private static final int EXPECTED_CHANGING_CONFIG =
+ ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_LOCALE;
+
+ private TypedArray mTypedArray;
@Override
protected void setUp() throws Exception {
super.setUp();
- final int[] attrs = R.styleable.style1;
- mTypedArray = getContext().getTheme().obtainStyledAttributes(R.style.Whatever, attrs);
+ mTypedArray = getContext().getTheme().obtainStyledAttributes(R.style.Whatever, R.styleable.style1);
}
@Override
@@ -69,85 +70,126 @@
mTypedArray.recycle();
}
- /*
- * Test all get attrs methods, all test value are in styles.xml and attrs.xml.
- */
- public void testAttrsMethod() {
- // getBoolean test
- assertTrue(mTypedArray.getBoolean(R.styleable.style1_type1, false));
- assertFalse(mTypedArray.getBoolean(R.styleable.style1_type2, true));
+ public void testGetType() {
+ final TypedArray t = getContext().getTheme().obtainStyledAttributes(
+ R.style.Whatever, R.styleable.style1);
- assertEquals(EXPECTEDCLOLOR, mTypedArray.getColor(R.styleable.style1_type3, DEFINT));
+ assertEquals(TypedValue.TYPE_INT_BOOLEAN, t.getType(R.styleable.style1_type1));
+ assertEquals(TypedValue.TYPE_INT_BOOLEAN, t.getType(R.styleable.style1_type2));
+ assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, t.getType(R.styleable.style1_type3));
+ assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, t.getType(R.styleable.style1_type4));
+ assertEquals(TypedValue.TYPE_DIMENSION, t.getType(R.styleable.style1_type5));
+ assertEquals(TypedValue.TYPE_DIMENSION, t.getType(R.styleable.style1_type6));
+ assertEquals(TypedValue.TYPE_DIMENSION, t.getType(R.styleable.style1_type7));
+ assertEquals(TypedValue.TYPE_STRING, t.getType(R.styleable.style1_type8));
+ assertEquals(TypedValue.TYPE_FLOAT, t.getType(R.styleable.style1_type9));
+ assertEquals(TypedValue.TYPE_FRACTION, t.getType(R.styleable.style1_type10));
+ assertEquals(TypedValue.TYPE_INT_DEC, t.getType(R.styleable.style1_type11));
+ assertEquals(TypedValue.TYPE_INT_DEC, t.getType(R.styleable.style1_type12));
+ assertEquals(TypedValue.TYPE_STRING, t.getType(R.styleable.style1_type13));
+ assertEquals(TypedValue.TYPE_STRING, t.getType(R.styleable.style1_type14));
+ assertEquals(TypedValue.TYPE_REFERENCE, t.getType(R.styleable.style1_type15));
+ assertEquals(TypedValue.TYPE_STRING, t.getType(R.styleable.style1_type16));
+ assertEquals(TypedValue.TYPE_NULL, t.getType(R.styleable.style1_typeEmpty));
+ assertEquals(TypedValue.TYPE_NULL, t.getType(R.styleable.style1_typeUndefined));
- // getColorStateList test
- final int[] set = new int[1];
- set[0] = 0;
+ t.recycle();
+ }
+
+ public void testBasics() {
+ final TypedArray t = getContext().getTheme().obtainStyledAttributes(
+ R.style.Whatever, R.styleable.style1);
+
+ assertEquals(EXPECTED_CHANGING_CONFIG, t.getChangingConfigurations());
+ assertEquals(EXPECTED_INDEX_COUNT, t.getIndexCount());
+ assertEquals(EXPTECTED_POS_DESCRIP, t.getPositionDescription());
+ assertEquals(EXPECTED_LENGTH, t.length());
+ assertEquals(getContext().getResources(), t.getResources());
+ assertNotNull(t.toString());
+
+ t.recycle();
+ }
+
+ public void testGetAttributes() {
+ final TypedArray t = getContext().getTheme().obtainStyledAttributes(
+ R.style.Whatever, R.styleable.style1);
+
+ assertTrue(t.getBoolean(R.styleable.style1_type1, false));
+ assertFalse(t.getBoolean(R.styleable.style1_type2, true));
+
+ assertEquals(EXPECTED_COLOR,
+ t.getColor(R.styleable.style1_type3, DEFINT));
assertEquals(EXPECTED_COLOR_STATE,
- mTypedArray.getColorStateList(R.styleable.style1_type4).
- getColorForState(set, DEFINT));
+ t.getColorStateList(R.styleable.style1_type4).getDefaultColor());
// This get values equals attribute dimension value set in styles.xml
// multiplied by the appropriate metric, the metric is unknown.
assertEquals(EXPECTED_DIMENSION,
- mTypedArray.getDimension(R.styleable.style1_type5, DEFFLOAT));
+ t.getDimension(R.styleable.style1_type5, DEFFLOAT));
+
assertEquals(EXPECTED_PIXEL_OFFSET,
- mTypedArray.getDimensionPixelOffset(R.styleable.style1_type6, DEFINT));
+ t.getDimensionPixelOffset(R.styleable.style1_type6, DEFINT));
assertEquals(EXPECTED_LAYOUT_DIMENSION,
- mTypedArray.getLayoutDimension(R.styleable.style1_type6, "type6"));
+ t.getLayoutDimension(R.styleable.style1_type6, "type6"));
assertEquals(EXPECTED_LAYOUT_DIMENSION,
- mTypedArray.getLayoutDimension(R.styleable.style1_type6, 0));
+ t.getLayoutDimension(R.styleable.style1_type6, 0));
+
assertEquals(EXPECTED_PIXEL_SIZE,
- mTypedArray.getDimensionPixelSize(R.styleable.style1_type7, DEFINT));
+ t.getDimensionPixelSize(R.styleable.style1_type7, DEFINT));
- // getDrawable test
- assertNotNull(mTypedArray.getDrawable(R.styleable.style1_type8));
- // getResourceId test
- assertEquals(R.drawable.pass,
- mTypedArray.getResourceId(R.styleable.style1_type8, DEFINT));
+ assertNotNull(t.getDrawable(R.styleable.style1_type8));
+ assertEquals(R.drawable.pass, t.getResourceId(R.styleable.style1_type8, DEFINT));
- assertEquals(EXPECTED_FLOAT, mTypedArray.getFloat(R.styleable.style1_type9, DEFFLOAT));
-
+ assertEquals(EXPECTED_FLOAT,
+ t.getFloat(R.styleable.style1_type9, DEFFLOAT));
assertEquals(EXPECTED_FRACTION,
- mTypedArray.getFraction(R.styleable.style1_type10, 10, 10, DEFFLOAT));
+ t.getFraction(R.styleable.style1_type10, 10, 10, DEFFLOAT));
+ assertEquals(EXPECTED_INT,
+ t.getInt(R.styleable.style1_type11, DEFINT));
+ assertEquals(EXPECTED_INT_ATT,
+ t.getInteger(R.styleable.style1_type12, DEFINT));
- assertEquals(EXPECTED_INT, mTypedArray.getInt(R.styleable.style1_type11, DEFINT));
+ assertEquals(EXPECTED_STRING, t.getString(R.styleable.style1_type13));
+ assertNull(t.getNonResourceString(R.styleable.style1_type14));
+ assertEquals(EXPECTED_TEXT, t.getText(R.styleable.style1_type14));
- assertEquals(EXPECTED_INT_ATT, mTypedArray.getInteger(R.styleable.style1_type12, DEFINT));
-
- assertEquals(EXPECTED_STRING, mTypedArray.getString(R.styleable.style1_type13));
-
- // getNonResourceString test
- assertNull(mTypedArray.getNonResourceString(R.styleable.style1_type14));
-
- assertEquals(EXPECTED_TEXT, mTypedArray.getText(R.styleable.style1_type14));
-
- CharSequence[] textArray = mTypedArray.getTextArray(R.styleable.style1_type15);
+ final CharSequence[] textArray = t.getTextArray(R.styleable.style1_type15);
assertEquals(EXPECTED_TEXT_ARRAY[0], textArray[0]);
assertEquals(EXPECTED_TEXT_ARRAY[1], textArray[1]);
assertEquals(EXPECTED_TEXT_ARRAY[2], textArray[2]);
- // getIndex test
- int index = mTypedArray.getIndex(R.styleable.style1_type16);
- assertEquals(EXPETED_INDEX, index);
- assertTrue(mTypedArray.getValue(index, DEF_VALUE));
- // hasValue test
- assertTrue(mTypedArray.hasValue(R.styleable.style1_type16));
+ final int index = t.getIndex(R.styleable.style1_type16);
+ assertEquals(EXPECTED_INDEX, index);
+ assertTrue(t.getValue(index, DEF_VALUE));
+ }
- // peekValue test
- assertNotNull(mTypedArray.peekValue(R.styleable.style1_type16));
+ public void testPeekValue() {
+ final TypedArray t = getContext().getTheme().obtainStyledAttributes(
+ R.style.Whatever, R.styleable.style1);
- assertEquals(EXPECTED_INDEX_COUNT, mTypedArray.getIndexCount());
+ final TypedValue v = t.peekValue(R.styleable.style1_type11);
+ assertNotNull(v);
+ assertEquals(TypedValue.TYPE_INT_DEC, v.type);
+ assertEquals(EXPECTED_INT, v.data);
- assertEquals(EXPTECTED_POS_DESCRIP,
- mTypedArray.getPositionDescription());
+ t.recycle();
+ }
- // getResources test
- assertEquals(getContext().getResources(), mTypedArray.getResources());
+ public void testHasValue() {
+ final TypedArray t = getContext().getTheme().obtainStyledAttributes(
+ R.style.Whatever, R.styleable.style1);
- assertEquals(EXPECTED_LENGTH, mTypedArray.length());
+ // hasValue()
+ assertTrue(t.hasValue(R.styleable.style1_type16));
+ assertFalse(t.hasValue(R.styleable.style1_typeEmpty));
+ assertFalse(t.hasValue(R.styleable.style1_typeUndefined));
- // toString test
- assertNotNull(mTypedArray.toString());
+ // hasValueOrEmpty()
+ assertTrue(t.hasValueOrEmpty(R.styleable.style1_type16));
+ assertTrue(t.hasValueOrEmpty(R.styleable.style1_typeEmpty));
+ assertFalse(t.hasValueOrEmpty(R.styleable.style1_typeUndefined));
+
+ t.recycle();
}
public void testRecycle() {
diff --git a/tests/tests/display/Android.mk b/tests/tests/display/Android.mk
index 2b81ec1..5de5610 100644
--- a/tests/tests/display/Android.mk
+++ b/tests/tests/display/Android.mk
@@ -27,7 +27,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test platform-test-annotations
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 1f9f8d1..1d1db2b 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -28,6 +28,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.Presubmit;
import android.test.InstrumentationTestCase;
import android.util.DisplayMetrics;
import android.view.Display;
@@ -139,6 +140,7 @@
/**
* Verify that the WindowManager returns the default display.
*/
+ @Presubmit
public void testDefaultDisplay() {
assertEquals(Display.DEFAULT_DISPLAY, mWindowManager.getDefaultDisplay().getDisplayId());
}
diff --git a/tests/tests/dpi/Android.mk b/tests/tests/dpi/Android.mk
index 0c158121..3f4cde5 100644
--- a/tests/tests/dpi/Android.mk
+++ b/tests/tests/dpi/Android.mk
@@ -17,7 +17,7 @@
include $(CLEAR_VARS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index e722646..fc38fdd 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.util.DisplayMetrics;
import android.view.Display;
@@ -31,6 +32,7 @@
*/
public class ConfigurationTest extends AndroidTestCase {
+ @Presubmit
public void testScreenConfiguration() {
WindowManager windowManager =
(WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
diff --git a/tests/tests/externalservice/Android.mk b/tests/tests/externalservice/Android.mk
index 3adfc34..c438dd6 100644
--- a/tests/tests/externalservice/Android.mk
+++ b/tests/tests/externalservice/Android.mk
@@ -36,7 +36,7 @@
LOCAL_PACKAGE_NAME := CtsExternalServiceTestCases
-LOCAL_SDK_VERSION := system_current
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/externalservice/service/Android.mk b/tests/tests/externalservice/service/Android.mk
index 68e9d1a..9541b0e 100644
--- a/tests/tests/externalservice/service/Android.mk
+++ b/tests/tests/externalservice/service/Android.mk
@@ -30,6 +30,6 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
-LOCAL_SDK_VERSION := system_current
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/externalservice/src/android/externalservice/cts/ExternalServiceTest.java b/tests/tests/externalservice/src/android/externalservice/cts/ExternalServiceTest.java
index b80b2ff..37c8613 100644
--- a/tests/tests/externalservice/src/android/externalservice/cts/ExternalServiceTest.java
+++ b/tests/tests/externalservice/src/android/externalservice/cts/ExternalServiceTest.java
@@ -31,7 +31,6 @@
import android.os.RemoteException;
import android.test.AndroidTestCase;
import android.util.Log;
-import android.util.MutableInt;
import android.externalservice.common.ServiceMessages;
@@ -140,15 +139,13 @@
// Check the identity of the service.
Messenger remote = new Messenger(mConnection.service);
- MutableInt uid = new MutableInt(0);
- MutableInt pid = new MutableInt(0);
- StringBuilder pkg = new StringBuilder();
- assertTrue(identifyService(remote, uid, pid, pkg));
+ ServiceIdentity id = identifyService(remote);
+ assertNotNull(id);
- assertFalse(uid.value == 0 || pid.value == 0);
- assertNotEquals(Process.myUid(), uid.value);
- assertNotEquals(Process.myPid(), pid.value);
- assertEquals(getContext().getPackageName(), pkg.toString());
+ assertFalse(id.uid == 0 || id.pid == 0);
+ assertNotEquals(Process.myUid(), id.uid);
+ assertNotEquals(Process.myPid(), id.pid);
+ assertEquals(getContext().getPackageName(), id.packageName);
}
/** Tests that the APK providing the externalService can bind the service itself, and that
@@ -165,11 +162,9 @@
// Get the identity of the creator.
Messenger remoteCreator = new Messenger(creatorConnection.service);
- MutableInt creatorUid = new MutableInt(0);
- MutableInt creatorPid = new MutableInt(0);
- StringBuilder creatorPkg = new StringBuilder();
- assertTrue(identifyService(remoteCreator, creatorUid, creatorPid, creatorPkg));
- assertFalse(creatorUid.value == 0 || creatorPid.value == 0);
+ ServiceIdentity creatorId = identifyService(remoteCreator);
+ assertNotNull(creatorId);
+ assertFalse(creatorId.uid == 0 || creatorId.pid == 0);
// Have the creator actually start its service.
final Message creatorMsg =
@@ -201,12 +196,9 @@
// Get the connection to the creator's service.
assertNotNull(creatorMsg.obj);
Messenger remoteCreatorService = (Messenger) creatorMsg.obj;
- MutableInt creatorServiceUid = new MutableInt(0);
- MutableInt creatorServicePid = new MutableInt(0);
- StringBuilder creatorServicePkg = new StringBuilder();
- assertTrue(identifyService(remoteCreatorService, creatorServiceUid, creatorServicePid,
- creatorServicePkg));
- assertFalse(creatorServiceUid.value == 0 || creatorPid.value == 0);
+ ServiceIdentity creatorServiceId = identifyService(remoteCreatorService);
+ assertNotNull(creatorServiceId);
+ assertFalse(creatorServiceId.uid == 0 || creatorId.pid == 0);
// Create an external service from this (the test) process.
intent = new Intent();
@@ -216,37 +208,34 @@
assertTrue(getContext().bindService(intent, mConnection,
Context.BIND_AUTO_CREATE | Context.BIND_EXTERNAL_SERVICE));
assertTrue(mCondition.block(CONDITION_TIMEOUT));
- MutableInt serviceUid = new MutableInt(0);
- MutableInt servicePid = new MutableInt(0);
- StringBuilder servicePkg = new StringBuilder();
- assertTrue(identifyService(new Messenger(mConnection.service), serviceUid, servicePid,
- servicePkg));
- assertFalse(serviceUid.value == 0 || servicePid.value == 0);
+ ServiceIdentity serviceId = identifyService(new Messenger(mConnection.service));
+ assertNotNull(serviceId);
+ assertFalse(serviceId.uid == 0 || serviceId.pid == 0);
// Make sure that all the processes are unique.
int myUid = Process.myUid();
int myPid = Process.myPid();
String myPkg = getContext().getPackageName();
- assertNotEquals(myUid, creatorUid.value);
- assertNotEquals(myUid, creatorServiceUid.value);
- assertNotEquals(myUid, serviceUid.value);
- assertNotEquals(myPid, creatorPid.value);
- assertNotEquals(myPid, creatorServicePid.value);
- assertNotEquals(myPid, servicePid.value);
+ assertNotEquals(myUid, creatorId.uid);
+ assertNotEquals(myUid, creatorServiceId.uid);
+ assertNotEquals(myUid, serviceId.uid);
+ assertNotEquals(myPid, creatorId.pid);
+ assertNotEquals(myPid, creatorServiceId.pid);
+ assertNotEquals(myPid, serviceId.pid);
- assertNotEquals(creatorUid.value, creatorServiceUid.value);
- assertNotEquals(creatorUid.value, serviceUid.value);
- assertNotEquals(creatorPid.value, creatorServicePid.value);
- assertNotEquals(creatorPid.value, servicePid.value);
+ assertNotEquals(creatorId.uid, creatorServiceId.uid);
+ assertNotEquals(creatorId.uid, serviceId.uid);
+ assertNotEquals(creatorId.pid, creatorServiceId.pid);
+ assertNotEquals(creatorId.pid, serviceId.pid);
- assertNotEquals(creatorServiceUid.value, serviceUid.value);
- assertNotEquals(creatorServicePid.value, servicePid.value);
+ assertNotEquals(creatorServiceId.uid, serviceId.uid);
+ assertNotEquals(creatorServiceId.pid, serviceId.pid);
- assertNotEquals(myPkg, creatorPkg.toString());
- assertNotEquals(myPkg, creatorServicePkg.toString());
- assertEquals(creatorPkg.toString(), creatorServicePkg.toString());
- assertEquals(myPkg, servicePkg.toString());
+ assertNotEquals(myPkg, creatorId.packageName);
+ assertNotEquals(myPkg, creatorServiceId.packageName);
+ assertEquals(creatorId.packageName, creatorServiceId.packageName);
+ assertEquals(myPkg, serviceId.packageName);
getContext().unbindService(creatorConnection);
}
@@ -264,11 +253,9 @@
assertTrue(mCondition.block(CONDITION_TIMEOUT));
- MutableInt uidOne = new MutableInt(0);
- MutableInt pidOne = new MutableInt(0);
- StringBuilder pkgOne = new StringBuilder();
- assertTrue(identifyService(new Messenger(initialConn.service), uidOne, pidOne, pkgOne));
- assertFalse(uidOne.value == 0 || pidOne.value == 0);
+ ServiceIdentity idOne = identifyService(new Messenger(initialConn.service));
+ assertNotNull(idOne);
+ assertFalse(idOne.uid == 0 || idOne.pid == 0);
// Bind the service with a different priority.
mCondition.close();
@@ -279,38 +266,41 @@
assertTrue(mCondition.block(CONDITION_TIMEOUT));
- MutableInt uidTwo = new MutableInt(0);
- MutableInt pidTwo = new MutableInt(0);
- StringBuilder pkgTwo = new StringBuilder();
- Messenger prioMessenger = new Messenger(prioConn.service);
- assertTrue(identifyService(prioMessenger, uidTwo, pidTwo, pkgTwo));
- assertFalse(uidTwo.value == 0 || pidTwo.value == 0);
+ ServiceIdentity idTwo = identifyService(new Messenger(prioConn.service));
+ assertNotNull(idTwo);
+ assertFalse(idTwo.uid == 0 || idTwo.pid == 0);
- assertEquals(uidOne.value, uidTwo.value);
- assertEquals(pidOne.value, pidTwo.value);
- assertEquals(pkgOne.toString(), pkgTwo.toString());
- assertNotEquals(Process.myUid(), uidOne.value);
- assertNotEquals(Process.myPid(), pidOne.value);
- assertEquals(getContext().getPackageName(), pkgOne.toString());
+ assertEquals(idOne.uid, idTwo.uid);
+ assertEquals(idOne.pid, idTwo.pid);
+ assertEquals(idOne.packageName, idTwo.packageName);
+ assertNotEquals(Process.myUid(), idOne.uid);
+ assertNotEquals(Process.myPid(), idOne.pid);
+ assertEquals(getContext().getPackageName(), idOne.packageName);
getContext().unbindService(prioConn);
getContext().unbindService(initialConn);
}
- /** Given a Messenger, this will message the service to retrieve its UID, PID, and package name,
- * storing the results in the mutable parameters. */
- private boolean identifyService(Messenger service, final MutableInt uid, final MutableInt pid,
- final StringBuilder packageName) {
+ /** Contains information about the security principal of a Service. */
+ private static class ServiceIdentity {
+ int uid;
+ int pid;
+ String packageName;
+ }
+
+ /** Given a Messenger, this will message the service to retrieve its UID, PID, and package name.
+ * On success, returns a ServiceIdentity. On failure, returns null. */
+ private ServiceIdentity identifyService(Messenger service) {
+ final ServiceIdentity id = new ServiceIdentity();
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "Received message: " + msg);
switch (msg.what) {
case ServiceMessages.MSG_IDENTIFY_RESPONSE:
- uid.value = msg.arg1;
- pid.value = msg.arg2;
- packageName.append(
- msg.getData().getString(ServiceMessages.IDENTIFY_PACKAGE));
+ id.uid = msg.arg1;
+ id.pid = msg.arg2;
+ id.packageName = msg.getData().getString(ServiceMessages.IDENTIFY_PACKAGE);
mCondition.open();
break;
}
@@ -326,10 +316,12 @@
service.send(msg);
} catch (RemoteException e) {
fail("Unexpected remote exception: " + e);
- return false;
+ return null;
}
- return mCondition.block(CONDITION_TIMEOUT);
+ if (!mCondition.block(CONDITION_TIMEOUT))
+ return null;
+ return id;
}
private class Connection implements ServiceConnection {
diff --git a/tests/tests/graphics/res/color/fill_gradient_linear.xml b/tests/tests/graphics/res/color/fill_gradient_linear.xml
index e0e3f03..d9b7497 100644
--- a/tests/tests/graphics/res/color/fill_gradient_linear.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_linear.xml
@@ -18,8 +18,8 @@
-->
<gradient xmlns:android="http://schemas.android.com/apk/res/android"
android:angle="90"
- android:startColor="?android:attr/colorPrimary"
- android:endColor="?android:attr/colorControlActivated"
+ android:startColor="?attr/themeColor"
+ android:endColor="#0f0"
android:centerColor="#00ff0000"
android:startX="0"
android:startY="0"
diff --git a/tests/tests/graphics/res/color/fill_gradient_linear_clamp.xml b/tests/tests/graphics/res/color/fill_gradient_linear_clamp.xml
new file mode 100644
index 0000000..56d9fc8
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_linear_clamp.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?attr/themeColor"
+ android:endColor="#0f0"
+ android:centerColor="#00ff0000"
+ android:startX="0"
+ android:startY="0"
+ android:endX="50"
+ android:endY="50"
+ android:type="linear"
+ android:tileMode="clamp">
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_linear_item.xml b/tests/tests/graphics/res/color/fill_gradient_linear_item.xml
index cfb1236..c1fb560 100644
--- a/tests/tests/graphics/res/color/fill_gradient_linear_item.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_linear_item.xml
@@ -18,15 +18,15 @@
-->
<gradient xmlns:android="http://schemas.android.com/apk/res/android"
android:angle="90"
- android:startColor="?android:attr/colorPrimary"
- android:endColor="?android:attr/colorControlActivated"
+ android:startColor="?attr/themeColor"
+ android:endColor="#0f0"
android:centerColor="#f00"
android:startX="0"
android:startY="0"
android:endX="100"
android:endY="100"
android:type="linear">
- <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
<item android:offset="0.4" android:color="#fff"/>
- <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="0.9" android:color="#0f0"/>
</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap.xml b/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap.xml
index 18274b9..a5b261a 100644
--- a/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap.xml
@@ -18,16 +18,16 @@
-->
<gradient xmlns:android="http://schemas.android.com/apk/res/android"
android:angle="90"
- android:startColor="?android:attr/colorPrimary"
- android:endColor="?android:attr/colorControlActivated"
+ android:startColor="?attr/themeColor"
+ android:endColor="#0f0"
android:centerColor="#f00"
android:startX="0"
android:startY="0"
android:endX="100"
android:endY="100"
android:type="linear">
- <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
<item android:offset="0.4" android:color="#f00"/>
<item android:offset="0.4" android:color="#fff"/>
- <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="0.9" android:color="#0f0"/>
</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap_mirror.xml b/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap_mirror.xml
new file mode 100644
index 0000000..009eb52
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_linear_item_overlap_mirror.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?attr/themeColor"
+ android:endColor="#0f0"
+ android:centerColor="#f00"
+ android:startX="0"
+ android:startY="0"
+ android:endX="50"
+ android:endY="50"
+ android:type="linear"
+ android:tileMode="mirror">
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.4" android:color="#f00"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="#0f0"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_linear_item_repeat.xml b/tests/tests/graphics/res/color/fill_gradient_linear_item_repeat.xml
new file mode 100644
index 0000000..c89e981
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_linear_item_repeat.xml
@@ -0,0 +1,33 @@
+<?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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?attr/themeColor"
+ android:endColor="#0f0"
+ android:centerColor="#f00"
+ android:startX="0"
+ android:startY="0"
+ android:endX="50"
+ android:endY="50"
+ android:type="linear"
+ android:tileMode="repeat">
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="#0f0"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_radial.xml b/tests/tests/graphics/res/color/fill_gradient_radial.xml
index ef6fd70..389a0fc 100644
--- a/tests/tests/graphics/res/color/fill_gradient_radial.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_radial.xml
@@ -18,10 +18,10 @@
-->
<gradient xmlns:android="http://schemas.android.com/apk/res/android"
android:centerColor="#ff0000"
- android:endColor="?android:attr/colorControlActivated"
+ android:endColor="#0f0"
android:centerX="300"
android:centerY="300"
android:gradientRadius="100"
- android:startColor="?android:attr/colorPrimary"
+ android:startColor="?attr/themeColor"
android:type="radial">
</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_radial_clamp.xml b/tests/tests/graphics/res/color/fill_gradient_radial_clamp.xml
new file mode 100644
index 0000000..ff29134
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_radial_clamp.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#0f0"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="50"
+ android:startColor="?attr/themeColor"
+ android:type="radial"
+ android:tileMode="clamp">
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_radial_item.xml b/tests/tests/graphics/res/color/fill_gradient_radial_item.xml
index c6cea7c..2f116c9 100644
--- a/tests/tests/graphics/res/color/fill_gradient_radial_item.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_radial_item.xml
@@ -24,7 +24,7 @@
android:gradientRadius="100"
android:startColor="#ffffffff"
android:type="radial">
- <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
<item android:offset="0.4" android:color="#fff"/>
- <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="0.9" android:color="#0f0"/>
</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_radial_item_repeat.xml b/tests/tests/graphics/res/color/fill_gradient_radial_item_repeat.xml
new file mode 100644
index 0000000..d17fc48
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_radial_item_repeat.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="50"
+ android:startColor="#ffffffff"
+ android:type="radial"
+ android:tileMode="repeat">
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="#0f0"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_radial_item_short.xml b/tests/tests/graphics/res/color/fill_gradient_radial_item_short.xml
index fefbe9f..111d023 100644
--- a/tests/tests/graphics/res/color/fill_gradient_radial_item_short.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_radial_item_short.xml
@@ -21,6 +21,6 @@
android:centerY="300"
android:gradientRadius="100"
android:type="radial">
- <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
- <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.9" android:color="#0f0"/>
</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_radial_item_short_mirror.xml b/tests/tests/graphics/res/color/fill_gradient_radial_item_short_mirror.xml
new file mode 100644
index 0000000..1aa110c
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_radial_item_short_mirror.xml
@@ -0,0 +1,27 @@
+<?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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="50"
+ android:type="radial"
+ android:tileMode="mirror">
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.9" android:color="#0f0"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/fill_gradient_sweep_clamp.xml b/tests/tests/graphics/res/color/fill_gradient_sweep_clamp.xml
new file mode 100644
index 0000000..80f39f3
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_sweep_clamp.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:startColor="#ffffffff"
+ android:type="sweep"
+ android:tileMode="clamp">
+</gradient>
diff --git a/tests/tests/graphics/res/color/fill_gradient_sweep_item.xml b/tests/tests/graphics/res/color/fill_gradient_sweep_item.xml
index 332b9389..2a010c0 100644
--- a/tests/tests/graphics/res/color/fill_gradient_sweep_item.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_sweep_item.xml
@@ -24,7 +24,7 @@
android:gradientRadius="10"
android:startColor="#ffffffff"
android:type="sweep">
- <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
<item android:offset="0.4" android:color="#fff"/>
- <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="0.9" android:color="#0f0"/>
</gradient>
diff --git a/tests/tests/graphics/res/color/fill_gradient_sweep_item_long.xml b/tests/tests/graphics/res/color/fill_gradient_sweep_item_long.xml
index 3931288..7b0bbef 100644
--- a/tests/tests/graphics/res/color/fill_gradient_sweep_item_long.xml
+++ b/tests/tests/graphics/res/color/fill_gradient_sweep_item_long.xml
@@ -22,9 +22,9 @@
android:gradientRadius="10"
android:type="sweep">
<item android:offset="-0.3" android:color="#f00"/>
- <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
<item android:offset="0.4" android:color="#0f0"/>
<item android:offset="0.6" android:color="#00f"/>
- <item android:offset="0.7" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="0.7" android:color="#0f0"/>
<item android:offset="1.5" android:color="#00f"/>
</gradient>
diff --git a/tests/tests/graphics/res/color/fill_gradient_sweep_item_long_mirror.xml b/tests/tests/graphics/res/color/fill_gradient_sweep_item_long_mirror.xml
new file mode 100644
index 0000000..2a73a4f
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_sweep_item_long_mirror.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:type="sweep"
+ android:tileMode="mirror">
+ <item android:offset="-0.3" android:color="#f00"/>
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.4" android:color="#0f0"/>
+ <item android:offset="0.6" android:color="#00f"/>
+ <item android:offset="0.7" android:color="#0f0"/>
+ <item android:offset="1.5" android:color="#00f"/>
+</gradient>
diff --git a/tests/tests/graphics/res/color/fill_gradient_sweep_item_repeat.xml b/tests/tests/graphics/res/color/fill_gradient_sweep_item_repeat.xml
new file mode 100644
index 0000000..62e6f66
--- /dev/null
+++ b/tests/tests/graphics/res/color/fill_gradient_sweep_item_repeat.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:startColor="#ffffffff"
+ android:type="sweep"
+ android:tileMode="repeat">
+ <item android:offset="0.1" android:color="?attr/themeColor"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="#0f0"/>
+</gradient>
diff --git a/tests/tests/graphics/res/color/stroke_gradient_clamp.xml b/tests/tests/graphics/res/color/stroke_gradient_clamp.xml
new file mode 100644
index 0000000..3d746e7
--- /dev/null
+++ b/tests/tests/graphics/res/color/stroke_gradient_clamp.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:centerColor="#7f7f7f"
+ android:endColor="#ffffff"
+ android:startColor="#000000"
+ android:startX="0"
+ android:endX="50"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear"
+ android:tileMode="clamp">
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/stroke_gradient_item_alpha_mirror.xml b/tests/tests/graphics/res/color/stroke_gradient_item_alpha_mirror.xml
new file mode 100644
index 0000000..352a2fd
--- /dev/null
+++ b/tests/tests/graphics/res/color/stroke_gradient_item_alpha_mirror.xml
@@ -0,0 +1,29 @@
+<?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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:startX="0"
+ android:endX="50"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear"
+ android:tileMode="mirror">
+ <item android:offset="0.1" android:color="#f00"/>
+ <item android:offset="0.2" android:color="#2f0f"/>
+ <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/stroke_gradient_item_repeat.xml b/tests/tests/graphics/res/color/stroke_gradient_item_repeat.xml
new file mode 100644
index 0000000..42281d1
--- /dev/null
+++ b/tests/tests/graphics/res/color/stroke_gradient_item_repeat.xml
@@ -0,0 +1,33 @@
+<?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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:centerColor="#7f7f7f"
+ android:endColor="#ffffff"
+ android:startColor="#000000"
+ android:startX="0"
+ android:endX="50"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear"
+ android:tileMode="repeat">
+ <item android:offset="0.1" android:color="#f00"/>
+ <item android:offset="0.2" android:color="#f0f"/>
+ <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
new file mode 100644
index 0000000..bef75d4
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
new file mode 100644
index 0000000..85cf20b
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
new file mode 100644
index 0000000..a137784
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
index 638802f..d5288d1 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
index 1f248e3..54fbca7 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
new file mode 100644
index 0000000..40432cd
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index 085e72a..09fd92f 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
new file mode 100644
index 0000000..9f1b257
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/vector_icon_filltype_evenodd.xml b/tests/tests/graphics/res/drawable/vector_icon_filltype_evenodd.xml
new file mode 100644
index 0000000..d5d86d8
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_filltype_evenodd.xml
@@ -0,0 +1,33 @@
+<?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.
+ */
+-->
+<vector android:height="24dp" android:viewportHeight="400.0"
+ android:viewportWidth="1200.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillType="evenOdd"
+ android:fillColor="#f00"
+ android:pathData="M250,75L323,301 131,161 369,161 177,301z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="evenOdd"
+ android:fillColor="#f00"
+ android:pathData="M600,81A107,107 0,0 1,600 295A107,107 0,0 1,600 81zM600,139A49,49 0,0 1,600 237A49,49 0,0 1,600 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="evenOdd"
+ android:fillColor="#f00"
+ android:pathData="M950,81A107,107 0,0 1,950 295A107,107 0,0 1,950 81zM950,139A49,49 0,0 0,950 237A49,49 0,0 0,950 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_filltype_nonzero.xml b/tests/tests/graphics/res/drawable/vector_icon_filltype_nonzero.xml
new file mode 100644
index 0000000..9754e4b
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_filltype_nonzero.xml
@@ -0,0 +1,33 @@
+<?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.
+ */
+-->
+<vector android:height="24dp" android:viewportHeight="400.0"
+ android:viewportWidth="1200.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillType="nonZero"
+ android:fillColor="#f00"
+ android:pathData="M250,75L323,301 131,161 369,161 177,301z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="nonZero"
+ android:fillColor="#f00"
+ android:pathData="M600,81A107,107 0,0 1,600 295A107,107 0,0 1,600 81zM600,139A49,49 0,0 1,600 237A49,49 0,0 1,600 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="nonZero"
+ android:fillColor="#f00"
+ android:pathData="M950,81A107,107 0,0 1,950 295A107,107 0,0 1,950 81zM950,139A49,49 0,0 0,950 237A49,49 0,0 0,950 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_gradient_1_clamp.xml b/tests/tests/graphics/res/drawable/vector_icon_gradient_1_clamp.xml
new file mode 100644
index 0000000..2fa440a
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_gradient_1_clamp.xml
@@ -0,0 +1,91 @@
+<?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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_clamp"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_clamp"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_clamp"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_clamp"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_clamp"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_clamp"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="@color/fill_gradient_linear_clamp"
+ android:strokeColor="@color/stroke_gradient_clamp"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_gradient_2_repeat.xml b/tests/tests/graphics/res/drawable/vector_icon_gradient_2_repeat.xml
new file mode 100644
index 0000000..5a43f80
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_gradient_2_repeat.xml
@@ -0,0 +1,90 @@
+<?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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_item_repeat"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_item_repeat"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_item_repeat"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_repeat"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_repeat"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_repeat"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_repeat"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_gradient_3_mirror.xml b/tests/tests/graphics/res/drawable/vector_icon_gradient_3_mirror.xml
new file mode 100644
index 0000000..e8de7c2
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_gradient_3_mirror.xml
@@ -0,0 +1,90 @@
+<?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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_item_overlap_mirror"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_item_short_mirror"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_item_long_mirror"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha_mirror"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha_mirror"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha_mirror"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/layout/animated_vector_drawable_source.xml b/tests/tests/graphics/res/layout/animated_vector_drawable_source.xml
new file mode 100644
index 0000000..57f268f
--- /dev/null
+++ b/tests/tests/graphics/res/layout/animated_vector_drawable_source.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.
+-->
+
+<!-- Demonstrates a simple layout with AnimatedVectorDrawable in an ImageView. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id = "@+id/avd_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/animation_vector_drawable_grouping_1"/>
+
+</LinearLayout>
diff --git a/tests/tests/graphics/src/android/graphics/cts/AvoidXfermodeTest.java b/tests/tests/graphics/src/android/graphics/cts/AvoidXfermodeTest.java
deleted file mode 100644
index beb3621..0000000
--- a/tests/tests/graphics/src/android/graphics/cts/AvoidXfermodeTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 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.graphics.cts;
-
-import android.graphics.AvoidXfermode;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
-
-import junit.framework.TestCase;
-
-public class AvoidXfermodeTest extends TestCase {
- /*
- * ToBeFixed: This test ought to work with a TOLERANCE of 0. See bug 2034547.
- */
- private static final int TOLERANCE = 255;
- private static final int BASE_SIZE = 50;
- private static final int BITMAP_HEIGHT = BASE_SIZE * 2;
- private static final int BITMAP_WIDTH = BASE_SIZE * 2;
-
- public void testAvoidXfermode() {
- Paint greenPaint;
- Paint redAvoidingGreenPaint;
- Paint blueTargetingGreenPaint;
- greenPaint = new Paint();
- greenPaint.setColor(Color.GREEN);
- AvoidXfermode avoidMode =
- new AvoidXfermode(greenPaint.getColor(), TOLERANCE, AvoidXfermode.Mode.AVOID);
- redAvoidingGreenPaint = new Paint();
- redAvoidingGreenPaint.setColor(Color.RED);
- redAvoidingGreenPaint.setXfermode(avoidMode);
- AvoidXfermode targetMode =
- new AvoidXfermode(greenPaint.getColor(), TOLERANCE, AvoidXfermode.Mode.TARGET);
- blueTargetingGreenPaint = new Paint();
- blueTargetingGreenPaint.setColor(Color.BLUE);
- blueTargetingGreenPaint.setXfermode(targetMode);
-
- Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
- b.eraseColor(Color.BLACK);
- Canvas canvas = new Canvas(b);
- // vertical bar on the left
- canvas.drawRect(0f, 0f, BASE_SIZE, 2 * BASE_SIZE, greenPaint);
- // horizontal bar on top
- canvas.drawRect(0f, 0f, 2 * BASE_SIZE, BASE_SIZE, redAvoidingGreenPaint);
- // horizontal bar at bottom
- canvas.drawRect(0f, BASE_SIZE, 2 * BASE_SIZE, 2 * BASE_SIZE, blueTargetingGreenPaint);
-
- assertEquals(Color.GREEN, b.getPixel(BASE_SIZE / 2, BASE_SIZE / 2));
- assertEquals(Color.RED, b.getPixel(BASE_SIZE + BASE_SIZE / 2, BASE_SIZE / 2));
- assertEquals(Color.BLUE, b.getPixel(BASE_SIZE / 2, BASE_SIZE + BASE_SIZE / 2));
- assertEquals(Color.BLACK, b.getPixel(BASE_SIZE + BASE_SIZE / 2, BASE_SIZE + BASE_SIZE / 2));
- }
-}
diff --git a/tests/tests/graphics/src/android/graphics/cts/AvoidXfermode_ModeTest.java b/tests/tests/graphics/src/android/graphics/cts/AvoidXfermode_ModeTest.java
deleted file mode 100644
index 8704e6f..0000000
--- a/tests/tests/graphics/src/android/graphics/cts/AvoidXfermode_ModeTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.cts;
-
-import android.graphics.AvoidXfermode;
-import android.graphics.AvoidXfermode.Mode;
-import android.test.AndroidTestCase;
-
-public class AvoidXfermode_ModeTest extends AndroidTestCase{
-
- public void testValueOf(){
- assertEquals(Mode.AVOID, Mode.valueOf("AVOID"));
- assertEquals(Mode.TARGET, Mode.valueOf("TARGET"));
- }
-
- public void testValues(){
- Mode[] mode = Mode.values();
-
- assertEquals(2, mode.length);
- assertEquals(Mode.AVOID, mode[0]);
- assertEquals(Mode.TARGET, mode[1]);
-
- //Mode is used as a argument here for all the methods that use it
- assertNotNull(new AvoidXfermode(10, 24, Mode.AVOID));
- assertNotNull(new AvoidXfermode(10, 24, Mode.TARGET));
- }
-}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
index 1a2164a..b44faff 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
@@ -23,8 +23,8 @@
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
-import android.graphics.PixelXorXfermode;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.graphics.Bitmap.Config;
@@ -71,17 +71,17 @@
}
public void testXfermode() {
- Bitmap greenBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- greenBitmap.eraseColor(Color.GREEN);
+ Bitmap redBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+ redBitmap.eraseColor(Color.RED);
Bitmap cyanBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
cyanBitmap.eraseColor(Color.CYAN);
- BitmapShader blueShader = new BitmapShader(greenBitmap, TileMode.CLAMP, TileMode.CLAMP);
- BitmapShader redShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
+ BitmapShader redShader = new BitmapShader(redBitmap, TileMode.CLAMP, TileMode.CLAMP);
+ BitmapShader cyanShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
- PixelXorXfermode xferMode = new PixelXorXfermode(Color.WHITE);
+ PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
- ComposeShader shader = new ComposeShader(blueShader, redShader, xferMode);
+ ComposeShader shader = new ComposeShader(redShader, cyanShader, xferMode);
Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
@@ -89,7 +89,7 @@
paint.setShader(shader);
canvas.drawPaint(paint);
- // white ^ green ^ cyan = yellow
- assertEquals(Color.YELLOW, bitmap.getPixel(0, 0));
+ // green + cyan = white
+ assertEquals(Color.WHITE, bitmap.getPixel(0, 0));
}
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java b/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
new file mode 100644
index 0000000..4b01916
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.graphics.cts;
+
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@SmallTest
+public class OutlineTest {
+ @Test
+ public void testDefaults() {
+ Outline outline = new Outline();
+
+ assertEquals(0.0f, outline.getAlpha(), 0.0f);
+ assertTrue(outline.isEmpty());
+ Rect outRect = new Rect();
+ assertFalse(outline.getRect(outRect));
+ assertTrue(outline.getRadius() < 0);
+ }
+
+ @Test
+ public void testGetSetAlpha() {
+ Outline outline = new Outline();
+
+ outline.setAlpha(1.0f);
+ assertEquals(1.0f, outline.getAlpha(), 0.0f);
+
+ outline.setAlpha(0.0f);
+ assertEquals(0.0f, outline.getAlpha(), 0.0f);
+
+ outline.setAlpha(0.45f);
+ assertEquals(0.45f, outline.getAlpha(), 0.0f);
+
+ // define out of range getter/setter behavior: (note will be clamped in native when consumed)
+ outline.setAlpha(4f);
+ assertEquals(4f, outline.getAlpha(), 0.0f);
+ outline.setAlpha(-30f);
+ assertEquals(-30f, outline.getAlpha(), 0.0f);
+ }
+
+ @Test
+ public void testSetRect() {
+ Outline outline = new Outline();
+ Rect outRect = new Rect();
+
+ outline.setRect(0, 0, 0, 0);
+ assertTrue(outline.isEmpty());
+
+ outline.setRect(10, 5, 4, 5);
+ assertTrue(outline.isEmpty());
+
+ outline.setRect(new Rect());
+ assertTrue(outline.isEmpty());
+
+ outline.setRect(10, 10, 20, 20);
+ assertFalse(outline.isEmpty());
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(10, 10, 20, 20), outRect);
+ assertTrue(outline.canClip());
+
+ outline.setRect(new Rect(10, 10, 20, 20));
+ assertFalse(outline.isEmpty());
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(10, 10, 20, 20), outRect);
+ assertTrue(outline.canClip());
+ }
+
+ @Test
+ public void testSetRoundRect() {
+ Outline outline = new Outline();
+ Rect outRect = new Rect();
+
+ outline.setRoundRect(0, 0, 0, 0, 1f);
+ assertTrue(outline.isEmpty());
+
+ outline.setRoundRect(10, 5, 4, 5, 1f);
+ assertTrue(outline.isEmpty());
+
+ outline.setRoundRect(new Rect(), 1f);
+ assertTrue(outline.isEmpty());
+
+ outline.setRoundRect(10, 10, 20, 20, 5f);
+ assertFalse(outline.isEmpty());
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(10, 10, 20, 20), outRect);
+ assertEquals(5f, outline.getRadius(), 0.0f);
+ assertTrue(outline.canClip());
+
+ outline.setRoundRect(new Rect(10, 10, 20, 20), 4f);
+ assertFalse(outline.isEmpty());
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(10, 10, 20, 20), outRect);
+ assertEquals(4f, outline.getRadius(), 0.0f);
+ assertTrue(outline.canClip());
+ }
+
+ @Test
+ public void testSetOval() {
+ Outline outline = new Outline();
+
+ outline.setOval(0, 0, 0, 0);
+ assertTrue(outline.isEmpty());
+
+ outline.setOval(10, 5, 4, 5);
+ assertTrue(outline.isEmpty());
+
+ Rect outRect = new Rect();
+ outline.setOval(0, 0, 50, 51); // different x & y radii, so not round rect
+ assertFalse(outline.getRect(outRect)); // not round rect, doesn't work
+ assertFalse(outline.canClip()); // not round rect, doesn't work
+ assertFalse(outline.isEmpty());
+
+ outline.setOval(0, 0, 50, 50); // same x & y radii, so round rect
+ assertTrue(outline.getRect(outRect)); // is round rect, so works
+ assertTrue(outline.canClip()); // is round rect, so works
+ assertFalse(outline.isEmpty());
+ }
+
+ @Test
+ public void testSetConvexPath() {
+ Outline outline = new Outline();
+ Path path = new Path();
+
+ assertTrue(path.isEmpty());
+ outline.setConvexPath(path);
+ assertTrue(outline.isEmpty());
+
+ path.addCircle(50, 50, 50, Path.Direction.CW);
+ outline.setConvexPath(path);
+ assertFalse(outline.isEmpty());
+ }
+
+ @Test
+ public void testGetRectRadius() {
+ Outline outline = new Outline();
+
+ Rect outRect = new Rect();
+ outline.setRoundRect(15, 10, 45, 40, 30.0f);
+ assertEquals(30.0f, outline.getRadius(), 0.0f);
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(15, 10, 45, 40), outRect);
+
+ outline.setRect(5, 10, 15, 20);
+ assertEquals(0.0f, outline.getRadius(), 0.0f);
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(5, 10, 15, 20), outRect);
+
+ outline.setOval(0, 0, 50, 60);
+ assertTrue(outline.getRadius() < 0);
+ assertFalse(outline.getRect(outRect));
+ }
+
+ @Test
+ public void testOffset() {
+ Outline outline = new Outline();
+
+ Rect outRect = new Rect();
+ outline.setRoundRect(15, 10, 45, 40, 30.0f);
+ outline.offset(-15, -10);
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(0, 0, 30, 30), outRect);
+
+ outline.setRect(5, 10, 15, 20);
+ outline.offset(-5, -10);
+ assertTrue(outline.getRect(outRect));
+ assertEquals(new Rect(0, 0, 10, 10), outRect);
+ }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index c813bdb..92f31b0a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -28,6 +28,7 @@
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Rasterizer;
+import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
@@ -852,6 +853,57 @@
assertEquals(10.0f, p.getStrokeWidth());
}
+ public void testSetFontFeatureSettings() {
+ Paint p = new Paint();
+ // Roboto font (system default) has "fi" ligature
+ String text = "fi";
+ float[] widths = new float[text.length()];
+ p.getTextWidths(text, widths);
+ assertTrue(widths[0] > 0.0f);
+ assertEquals(0.0f, widths[1]);
+
+ // Disable ligature using OpenType feature
+ p.setFontFeatureSettings("'liga' off");
+ p.getTextWidths(text, widths);
+ assertTrue(widths[0] > 0.0f);
+ assertTrue(widths[1] > 0.0f);
+
+ // Re-enable ligature
+ p.setFontFeatureSettings("'liga' on");
+ p.getTextWidths(text, widths);
+ assertTrue(widths[0] > 0.0f);
+ assertEquals(0.0f, widths[1]);
+ }
+
+ public void testGetTextBounds() {
+ Paint p = new Paint();
+ p.setTextSize(10);
+ String text1 = "hello";
+ Rect bounds1 = new Rect();
+ Rect bounds2 = new Rect();
+ p.getTextBounds(text1, 0, text1.length(), bounds1);
+ char[] textChars1 = text1.toCharArray();
+ p.getTextBounds(textChars1, 0, textChars1.length, bounds2);
+ // verify that string and char array methods produce consistent results
+ assertEquals(bounds1, bounds2);
+ String text2 = "hello world";
+
+ // verify substring produces consistent results
+ p.getTextBounds(text2, 0, text1.length(), bounds2);
+ assertEquals(bounds1, bounds2);
+
+ // longer string is expected to have same left edge but be wider
+ p.getTextBounds(text2, 0, text2.length(), bounds2);
+ assertEquals(bounds1.left, bounds2.left);
+ assertTrue(bounds2.right > bounds1.right);
+
+ // bigger size implies bigger bounding rect
+ p.setTextSize(20);
+ p.getTextBounds(text1, 0, text1.length(), bounds2);
+ assertTrue(bounds2.right > bounds1.right);
+ assertTrue(bounds2.bottom - bounds2.top > bounds1.bottom - bounds1.top);
+ }
+
public void testReset() {
Paint p = new Paint();
ColorFilter c = new ColorFilter();
diff --git a/tests/tests/graphics/src/android/graphics/cts/PixelXorXfermodeTest.java b/tests/tests/graphics/src/android/graphics/cts/PixelXorXfermodeTest.java
deleted file mode 100644
index e2d68da..0000000
--- a/tests/tests/graphics/src/android/graphics/cts/PixelXorXfermodeTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.cts;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelXorXfermode;
-import android.graphics.Bitmap.Config;
-import android.test.AndroidTestCase;
-
-public class PixelXorXfermodeTest extends AndroidTestCase {
-
- public void testPixelXorXfermode() {
- int width = 100;
- int height = 100;
- Bitmap b1 = Bitmap.createBitmap(width / 2, height, Config.ARGB_8888);
- b1.eraseColor(Color.WHITE);
- Bitmap b2 = Bitmap.createBitmap(width, height / 2, Config.ARGB_8888);
- b2.eraseColor(Color.CYAN);
-
- Bitmap target = Bitmap.createBitmap(width, height, Config.ARGB_8888);
- target.eraseColor(Color.BLACK);
- Canvas canvas = new Canvas(target);
- Paint p = new Paint();
- canvas.drawBitmap(b1, 0, 0, p);
- p.setXfermode(new PixelXorXfermode(Color.GREEN));
- canvas.drawBitmap(b2, 0, height / 2, p);
- assertEquals(Color.WHITE, target.getPixel(width / 4, height / 4));
- // white ^ green ^ cyan = yellow
- assertEquals(Color.YELLOW, target.getPixel(width / 4, height * 3 / 4));
- // black ^ green ^ cyan = blue
- assertEquals(Color.BLUE, target.getPixel(width * 3 / 4, height * 3 / 4));
-
- // XOR transfer always results in an opaque image
- p.setXfermode(new PixelXorXfermode(alphaColor(Color.GREEN, 25)));
- target.eraseColor(alphaColor(Color.BLACK, 42));
- p.setColor(alphaColor(Color.CYAN, 5));
- canvas.drawPaint(p);
- // result is always opaque, even though all inputs have alpha
- assertEquals(255, Color.alpha(target.getPixel(0, 0)));
- }
-
- private int alphaColor(int color, int alpha) {
- int red = Color.red(color);
- int green = Color.green(color);
- int blue = Color.blue(color);
- return Color.argb(alpha, red, green, blue);
- }
-}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
index 8081ebb..92f3125 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -23,6 +23,7 @@
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
+import android.graphics.cts.R;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
@@ -33,8 +34,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
-
-import android.graphics.cts.R;
+import android.widget.ImageView;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -43,6 +43,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
+import static java.lang.Thread.sleep;
+
public class AnimatedVectorDrawableTest extends ActivityInstrumentationTestCase2<DrawableStubActivity> {
private static final String LOGTAG = AnimatedVectorDrawableTest.class.getSimpleName();
@@ -55,7 +57,10 @@
private Bitmap mBitmap;
private Canvas mCanvas;
private static final boolean DBG_DUMP_PNG = false;
- private int mResId = R.drawable.animation_vector_drawable_grouping_1;
+ private final int mResId = R.drawable.animation_vector_drawable_grouping_1;
+ private final int mLayoutId = R.layout.animated_vector_drawable_source;
+ private final int mImageViewId = R.id.avd_view;
+
public AnimatedVectorDrawableTest() {
super(DrawableStubActivity.class);
@@ -250,36 +255,81 @@
}
@MediumTest
- public void testAddCallback() {
- MyCallback callback = new MyCallback();
- final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
-
- d1.registerAnimationCallback(callback);
+ public void testAddCallbackBeforeStart() throws InterruptedException {
+ final MyCallback callback = new MyCallback();
// The AVD has a duration as 100ms.
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
+ mActivity.setContentView(mLayoutId);
+ ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+ AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+ d1.registerAnimationCallback(callback);
d1.start();
}
});
-
getInstrumentation().waitForIdleSync();
-
+ sleep(200);
assertTrue(callback.mStart);
assertTrue(callback.mEnd);
}
@MediumTest
- public void testRemoveCallback() {
- MyCallback callback = new MyCallback();
- final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
-
- d1.registerAnimationCallback(callback);
- assertTrue(d1.unregisterAnimationCallback(callback));
+ public void testAddCallbackAfterTrigger() throws InterruptedException {
+ final MyCallback callback = new MyCallback();
// The AVD has a duration as 100ms.
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
+ mActivity.setContentView(mLayoutId);
+ ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+ AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+ // This reset call can enforce the AnimatorSet is setup properly in AVD, when
+ // running on UI thread.
+ d1.reset();
+ d1.registerAnimationCallback(callback);
+ d1.start();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ sleep(200);
+ assertTrue(callback.mStart);
+ assertTrue(callback.mEnd);
+ }
+
+ @MediumTest
+ public void testAddCallbackAfterStart() throws InterruptedException {
+ final MyCallback callback = new MyCallback();
+ // The AVD has a duration as 100ms.
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.setContentView(mLayoutId);
+ ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+ AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+ d1.start();
+ d1.registerAnimationCallback(callback);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ sleep(200);
+ // Whether or not the callback.start is true could vary when running on Render Thread.
+ // Therefore, we don't make assertion here. The most useful flag is the callback.mEnd.
+ assertTrue(callback.mEnd);
+ }
+
+ @MediumTest
+ public void testRemoveCallback() {
+ final MyCallback callback = new MyCallback();
+ // The AVD has a duration as 100ms.
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.setContentView(mLayoutId);
+ ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+ AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+ d1.registerAnimationCallback(callback);
+ assertTrue(d1.unregisterAnimationCallback(callback));
d1.start();
}
});
@@ -291,15 +341,17 @@
@MediumTest
public void testClearCallback() {
- MyCallback callback = new MyCallback();
- final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
+ final MyCallback callback = new MyCallback();
- d1.registerAnimationCallback(callback);
- d1.clearAnimationCallbacks();
// The AVD has a duration as 100ms.
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
+ mActivity.setContentView(mLayoutId);
+ ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+ AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+ d1.registerAnimationCallback(callback);
+ d1.clearAnimationCallbacks();
d1.start();
}
});
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
index e2c0e0a..e78b04c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
@@ -78,7 +78,7 @@
}
private void helpTestSetEnterFadeDuration(int enterFadeDuration) {
- DrawableContainer container = new MockDrawableContainer();
+ DrawableContainer container = new LevelListDrawable();
DrawableContainerState cs = ((DrawableContainerState) container.getConstantState());
container.setEnterFadeDuration(enterFadeDuration);
assertEquals(enterFadeDuration, cs.getEnterFadeDuration());
@@ -90,7 +90,7 @@
}
private void helpTestSetExitFadeDuration(int exitFadeDuration) {
- DrawableContainer container = new MockDrawableContainer();
+ DrawableContainer container = new LevelListDrawable();
DrawableContainerState cs = ((DrawableContainerState) container.getConstantState());
container.setExitFadeDuration(exitFadeDuration);
assertEquals(exitFadeDuration, cs.getExitFadeDuration());
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index f174f01..a39c18f 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -46,7 +46,10 @@
public class VectorDrawableTest extends AndroidTestCase {
private static final String LOGTAG = "VectorDrawableTest";
- private static final int[] ICON_RES_IDS = new int[] {
+ // Separate the test assets into different groups such that we could isolate the issue faster.
+ // Some new APIs or bug fixes only exist in particular os version, such that we name the tests
+ // and associated assets with OS code name L, M, N etc...
+ private static final int[] BASIC_ICON_RES_IDS = new int[]{
R.drawable.vector_icon_create,
R.drawable.vector_icon_delete,
R.drawable.vector_icon_heart,
@@ -59,6 +62,24 @@
R.drawable.vector_icon_repeated_a_1,
R.drawable.vector_icon_repeated_a_2,
R.drawable.vector_icon_clip_path_1,
+ };
+
+ private static final int[] BASIC_GOLDEN_IMAGES = new int[] {
+ R.drawable.vector_icon_create_golden,
+ R.drawable.vector_icon_delete_golden,
+ R.drawable.vector_icon_heart_golden,
+ R.drawable.vector_icon_schedule_golden,
+ R.drawable.vector_icon_settings_golden,
+ R.drawable.vector_icon_random_path_1_golden,
+ R.drawable.vector_icon_random_path_2_golden,
+ R.drawable.vector_icon_repeated_cq_golden,
+ R.drawable.vector_icon_repeated_st_golden,
+ R.drawable.vector_icon_repeated_a_1_golden,
+ R.drawable.vector_icon_repeated_a_2_golden,
+ R.drawable.vector_icon_clip_path_1_golden,
+ };
+
+ private static final int[] L_M_ICON_RES_IDS = new int[] {
R.drawable.vector_icon_transformation_1,
R.drawable.vector_icon_transformation_2,
R.drawable.vector_icon_transformation_3,
@@ -72,23 +93,9 @@
R.drawable.vector_icon_stroke_3,
R.drawable.vector_icon_scale_1,
R.drawable.vector_icon_scale_2,
- R.drawable.vector_icon_implicit_lineto,
- R.drawable.vector_icon_arcto,
};
- private static final int[] GOLDEN_IMAGES = new int[] {
- R.drawable.vector_icon_create_golden,
- R.drawable.vector_icon_delete_golden,
- R.drawable.vector_icon_heart_golden,
- R.drawable.vector_icon_schedule_golden,
- R.drawable.vector_icon_settings_golden,
- R.drawable.vector_icon_random_path_1_golden,
- R.drawable.vector_icon_random_path_2_golden,
- R.drawable.vector_icon_repeated_cq_golden,
- R.drawable.vector_icon_repeated_st_golden,
- R.drawable.vector_icon_repeated_a_1_golden,
- R.drawable.vector_icon_repeated_a_2_golden,
- R.drawable.vector_icon_clip_path_1_golden,
+ private static final int[] L_M_GOLDEN_IMAGES = new int[] {
R.drawable.vector_icon_transformation_1_golden,
R.drawable.vector_icon_transformation_2_golden,
R.drawable.vector_icon_transformation_3_golden,
@@ -102,20 +109,38 @@
R.drawable.vector_icon_stroke_3_golden,
R.drawable.vector_icon_scale_1_golden,
R.drawable.vector_icon_scale_2_golden,
+ };
+
+ private static final int[] N_ICON_RES_IDS = new int[] {
+ R.drawable.vector_icon_implicit_lineto,
+ R.drawable.vector_icon_arcto,
+ R.drawable.vector_icon_filltype_nonzero,
+ R.drawable.vector_icon_filltype_evenodd,
+ };
+
+ private static final int[] N_GOLDEN_IMAGES = new int[] {
R.drawable.vector_icon_implicit_lineto_golden,
R.drawable.vector_icon_arcto_golden,
+ R.drawable.vector_icon_filltype_nonzero_golden,
+ R.drawable.vector_icon_filltype_evenodd_golden,
};
private static final int[] GRADIENT_ICON_RES_IDS = new int[] {
R.drawable.vector_icon_gradient_1,
R.drawable.vector_icon_gradient_2,
R.drawable.vector_icon_gradient_3,
+ R.drawable.vector_icon_gradient_1_clamp,
+ R.drawable.vector_icon_gradient_2_repeat,
+ R.drawable.vector_icon_gradient_3_mirror,
};
private static final int[] GRADIENT_GOLDEN_IMAGES = new int[] {
R.drawable.vector_icon_gradient_1_golden,
R.drawable.vector_icon_gradient_2_golden,
R.drawable.vector_icon_gradient_3_golden,
+ R.drawable.vector_icon_gradient_1_clamp_golden,
+ R.drawable.vector_icon_gradient_2_repeat_golden,
+ R.drawable.vector_icon_gradient_3_mirror_golden,
};
private static final int[] STATEFUL_RES_IDS = new int[] {
@@ -163,8 +188,18 @@
}
@MediumTest
- public void testSimpleVectorDrawables() throws XmlPullParserException, IOException {
- verifyVectorDrawables(ICON_RES_IDS, GOLDEN_IMAGES, null);
+ public void testBasicVectorDrawables() throws XmlPullParserException, IOException {
+ verifyVectorDrawables(BASIC_ICON_RES_IDS, BASIC_GOLDEN_IMAGES, null);
+ }
+
+ @MediumTest
+ public void testLMVectorDrawables() throws XmlPullParserException, IOException {
+ verifyVectorDrawables(L_M_ICON_RES_IDS, L_M_GOLDEN_IMAGES, null);
+ }
+
+ @MediumTest
+ public void testNVectorDrawables() throws XmlPullParserException, IOException {
+ verifyVectorDrawables(N_ICON_RES_IDS, N_GOLDEN_IMAGES, null);
}
@MediumTest
@@ -197,7 +232,9 @@
throw new XmlPullParserException("No start tag found");
}
- mVectorDrawable.inflate(mResources, parser, attrs, mContext.getTheme());
+ Theme theme = mResources.newTheme();
+ theme.applyStyle(R.style.Theme_ThemedDrawableTest, true);
+ mVectorDrawable.inflate(mResources, parser, attrs, theme);
if (stateSet != null) {
mVectorDrawable.setState(stateSet);
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 45aef43..a59c5f4 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -24,7 +24,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil compatibility-device-util platform-test-annotations
LOCAL_SDK_VERSION := current
@@ -52,7 +53,13 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner mockito-target android-ex-camera2
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil \
+ compatibility-device-util \
+ ctstestrunner \
+ mockito-target \
+ android-ex-camera2 \
+ platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
index 14027dd..68131d1 100644
--- a/tests/tests/hardware/AndroidTest.xml
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -26,6 +26,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.hardware.cts" />
+ <option name="runtime-hint" value="47m28s" />
</test>
</configuration>
diff --git a/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java b/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
index dc927b6..75d7b7c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
@@ -16,8 +16,8 @@
package android.hardware.cts;
-
import android.hardware.GeomagneticField;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import java.util.GregorianCalendar;
@@ -29,6 +29,7 @@
private static final float ALTITUDE_OF_CHENGDU = 500f;
private static final long TEST_TIME = new GregorianCalendar(2010, 5, 1).getTimeInMillis();
+ @Presubmit
public void testGeomagneticField() {
GeomagneticField geomagneticField = new GeomagneticField(LATITUDE_OF_CHENGDU,
LONGITUDE_OF_CHENGDU, ALTITUDE_OF_CHENGDU, TEST_TIME);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
index 2443004..1db2d51 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
@@ -24,6 +24,7 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
import android.hardware.cts.helpers.sensorverification.FifoLengthVerification;
+import android.platform.test.annotations.Presubmit;
import java.util.concurrent.TimeUnit;
@@ -46,6 +47,7 @@
PackageManager.FEATURE_HIFI_SENSORS);
}
+ @Presubmit
public void testAccelerometerFifoLength() throws Throwable {
if (!mHasHifiSensors) return;
runBatchingSensorFifoTest(
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
index 302ce72..bcd1734 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
@@ -90,6 +90,7 @@
context,
sensorType,
shouldEmulateSensorUnderLoad(),
+ true, /* isIntegrationTest */
sensor.getMinDelay(),
MAX_REPORTING_LATENCY_US);
TestSensorOperation batchingOperation =
@@ -143,6 +144,7 @@
context,
sensorType,
shouldEmulateSensorUnderLoad(),
+ true, /* isIntegrationTest */
generateSamplingRateInUs(sensorType),
generateReportLatencyInUs());
TestSensorOperation sensorOperation =
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 2bbf053..95a76b8 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -44,6 +44,7 @@
import android.os.HandlerThread;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import java.util.ArrayList;
@@ -200,6 +201,7 @@
// Some sensors like proximity, significant motion etc. are defined as wake-up sensors by
// default. Check if the wake-up flag is set correctly.
+ @Presubmit
public void testWakeUpFlags() {
final int TYPE_WAKE_GESTURE = 23;
final int TYPE_GLANCE_GESTURE = 24;
@@ -241,6 +243,7 @@
}
}
+ @Presubmit
public void testSensorStringTypes() {
for (Sensor sensor : mSensorList) {
if (sensor.getType() < MAX_OFFICIAL_ANDROID_SENSOR_TYPE &&
@@ -314,10 +317,14 @@
// TODO: remove when parameterized tests are supported (see SensorBatchingTests.java)
@TimeoutReq(minutes=20)
public void testBatchAndFlush() throws Exception {
+ // TODO - replace this constant once method to do so is made available
+ final int SENSOR_TYPE_DEVICE_PRIVATE_BASE = 0x10000;
SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
ArrayList<Throwable> errorsFound = new ArrayList<>();
for (Sensor sensor : mSensorList) {
- verifyRegisterListenerCallFlush(sensor, null /* handler */, errorsFound);
+ if (sensor.getType() < SENSOR_TYPE_DEVICE_PRIVATE_BASE) {
+ verifyRegisterListenerCallFlush(sensor, null /* handler */, errorsFound);
+ }
}
assertOnErrors(errorsFound);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
index 47c8313..6ef7938 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
@@ -23,6 +23,8 @@
import java.util.concurrent.TimeUnit;
+/* TODO: Refactor constructors into a builder */
+
/**
* A class that encapsulates base environment information for the {@link SensorOperation}.
* The environment is self contained and carries its state around all the sensor test framework.
@@ -41,6 +43,7 @@
private final int mSamplingPeriodUs;
private final int mMaxReportLatencyUs;
private final boolean mIsDeviceSuspendTest;
+ private final boolean mIsIntegrationTest;
/**
* Constructs an environment for sensor testing.
@@ -131,6 +134,34 @@
* Constructs an environment for sensor testing.
*
* @param context The context for the test
+ * @param sensorType The type of the sensor under test
+ * @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
+ * @param isIntegrationTest Whether this is an integration test (more than one sensor actived)
+ * @param samplingPeriodUs The requested collection period for the sensor under test
+ * @param maxReportLatencyUs The requested collection report latency for the sensor under test
+ *
+ * @deprecated Use variants with {@link Sensor} objects.
+ */
+ @Deprecated
+ public TestSensorEnvironment(
+ Context context,
+ int sensorType,
+ boolean sensorMightHaveMoreListeners,
+ boolean isIntegrationTest,
+ int samplingPeriodUs,
+ int maxReportLatencyUs) {
+ this(context,
+ getSensor(context, sensorType),
+ sensorMightHaveMoreListeners,
+ isIntegrationTest,
+ samplingPeriodUs,
+ maxReportLatencyUs);
+ }
+
+ /**
+ * Constructs an environment for sensor testing.
+ *
+ * @param context The context for the test
* @param sensor The sensor under test
* @param samplingPeriodUs The requested collection period for the sensor under test
* @param maxReportLatencyUs The requested collection report latency for the sensor under test
@@ -176,15 +207,46 @@
Context context,
Sensor sensor,
boolean sensorMightHaveMoreListeners,
+ boolean isIntegrationTest,
+ int samplingPeriodUs,
+ int maxReportLatencyUs) {
+ this(context,
+ sensor,
+ sensorMightHaveMoreListeners,
+ samplingPeriodUs,
+ maxReportLatencyUs,
+ false /* isDeviceSuspendTest */,
+ isIntegrationTest);
+ }
+
+ public TestSensorEnvironment(
+ Context context,
+ Sensor sensor,
+ boolean sensorMightHaveMoreListeners,
int samplingPeriodUs,
int maxReportLatencyUs,
boolean isDeviceSuspendTest) {
+ this(context, sensor, sensorMightHaveMoreListeners,
+ samplingPeriodUs, maxReportLatencyUs,
+ false /* isDeviceSuspendTest */,
+ false /* isIntegrationTest */);
+ }
+
+ public TestSensorEnvironment(
+ Context context,
+ Sensor sensor,
+ boolean sensorMightHaveMoreListeners,
+ int samplingPeriodUs,
+ int maxReportLatencyUs,
+ boolean isDeviceSuspendTest,
+ boolean isIntegrationTest) {
mContext = context;
mSensor = sensor;
mSensorMightHaveMoreListeners = sensorMightHaveMoreListeners;
mSamplingPeriodUs = samplingPeriodUs;
mMaxReportLatencyUs = maxReportLatencyUs;
mIsDeviceSuspendTest = isDeviceSuspendTest;
+ mIsIntegrationTest = isIntegrationTest;
}
/**
@@ -265,6 +327,7 @@
}
/**
+ * Calculate the maximum expected sampling period in us.
* @return The maximum acceptable actual sampling period of this sensor.
* For continuous sensors, this is higher than {@link #getExpectedSamplingPeriodUs()}
* because sensors are allowed to run up to 10% slower than requested.
@@ -282,6 +345,20 @@
return (int) (expectedSamplingPeriodUs / MAXIMUM_EXPECTED_SAMPLING_FREQUENCY_MULTIPLIER);
}
+
+ /**
+ * Calculate the allowed sensor start delay.
+ *
+ * CDD Section 7.3:
+ * MUST report the first sensor sample within 400 milliseconds + 2 * sample_time of the
+ * sensor being activated. It is acceptable for this sample to have an accuracy of 0.
+ *
+ * [CDD] Keep this updated with CDD.
+ */
+ public long getAllowedSensorStartDelay() {
+ return TimeUnit.MILLISECONDS.toMicros(400) + 2 * getMaximumExpectedSamplingPeriodUs();
+ }
+
/**
* @return The number of axes in the coordinate system of the sensor under test.
*/
@@ -378,5 +455,9 @@
public boolean isDeviceSuspendTest() {
return mIsDeviceSuspendTest;
}
+
+ public boolean isIntegrationTest() {
+ return mIsIntegrationTest;
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index dbe7c15..2da6a3b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -194,7 +194,8 @@
* It will overwrite the file if it already exists, the file is created in a relative directory
* named 'events' under the sensor test directory (part of external storage).
*/
- public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs)
+ public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs,
+ long testStartTimeMs, long testStopTimeMs)
throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
@@ -203,7 +204,11 @@
builder.append("RequestedSamplingPeriod=")
.append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
builder.append("MaxReportLatency=")
- .append(mEnvironment.getMaxReportLatencyUs()).append("us");
+ .append(mEnvironment.getMaxReportLatencyUs()).append("us, ");
+ builder.append("StartedTimestamp=")
+ .append(testStartTimeMs).append("ms, ");
+ builder.append("StoppedTimestamp=")
+ .append(testStopTimeMs).append("ms");
synchronized (mCollectedEvents) {
int i = 0, j = 0;
while (i < mCollectedEvents.size() && j < mTimeStampFlushCompleteEvents.size()) {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 779bb49..5ef2d3c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -66,6 +66,8 @@
private final Executor mExecutor;
private final Handler mHandler;
private long mDeviceWakeUpTimeMs = -1;
+ private long mStartTimeMs = -1;
+ private long mStopTimeMs = -1;
/**
* An interface that defines an abstraction for operations to be performed by the
@@ -124,20 +126,21 @@
getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
+ mStartTimeMs = SystemClock.elapsedRealtime();
if (mEnvironment.isDeviceSuspendTest()) {
SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor();
- long startTimeMs = SystemClock.elapsedRealtime();
// Device should go into suspend here.
mExecutor.execute(mSensorManager, listener);
- long endTimeMs = SystemClock.elapsedRealtime();
+ mStopTimeMs = SystemClock.elapsedRealtime();
// Check if the device has gone into suspend during test execution.
mDeviceWakeUpTimeMs = suspendStateMonitor.getLastWakeUpTime();
suspendStateMonitor.cancel();
Assert.assertTrue("Device did not go into suspend during test execution",
- startTimeMs < mDeviceWakeUpTimeMs &&
- mDeviceWakeUpTimeMs < endTimeMs);
+ mStartTimeMs < mDeviceWakeUpTimeMs &&
+ mDeviceWakeUpTimeMs < mStopTimeMs);
} else {
mExecutor.execute(mSensorManager, listener);
+ mStopTimeMs = SystemClock.elapsedRealtime();
}
boolean failed = false;
@@ -147,8 +150,8 @@
failed |= evaluateResults(collectedEvents, verification, sb);
}
+ trySaveCollectedEvents(parent, listener);
if (failed) {
- trySaveCollectedEvents(parent, listener);
String msg = SensorCtsHelper
.formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
getStats().addValue(SensorStats.ERROR, msg);
@@ -213,7 +216,8 @@
}
try {
- listener.logCollectedEventsToFile(sanitizedFileName, mDeviceWakeUpTimeMs);
+ listener.logCollectedEventsToFile(sanitizedFileName, mDeviceWakeUpTimeMs,
+ mStartTimeMs, mStopTimeMs);
} catch (IOException e) {
Log.w(TAG, "Unable to save collected events to file: " + sanitizedFileName, e);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
index 1e82b78..670c065 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
@@ -18,6 +18,7 @@
import junit.framework.Assert;
+import android.os.Build;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.cts.helpers.SensorStats;
@@ -28,15 +29,23 @@
import java.util.concurrent.TimeUnit;
/**
- * A {@link ISensorVerification} which verifies if the collected sensor events have any obvious
+ * A {@link ISensorVerification} which verifies if the collected sensor events have any obvious
* problems, such as no sample, wrong sensor type, etc.
*/
public class EventBasicVerification extends AbstractSensorVerification {
public static final String PASSED_KEY = "event_basic_passed";
- private static final long ALLOWED_SENSOR_DELIVERING_DELAY_US =
+ // allowed time from registration to sensor start sampling
+ private static final long ALLOWED_SENSOR_START_DELAY_US =
TimeUnit.MILLISECONDS.toMicros(1000);
+ // allowed time for entire sensor system to send sample to test app
+ private static final long ALLOWED_SENSOR_EVENT_LATENCY_US =
+ TimeUnit.MILLISECONDS.toMicros(1000);
+
+ // mercy added for recently added test. remove this mercy factor for next letter release.
+ private final float NUM_EVENT_MERCY_FACTOR; // 0~1, 0 means most strict
+
private final long mExpectedMinNumEvent;
private final Object mSensor;
private long mNumEvent;
@@ -56,6 +65,12 @@
mNumEvent = 0;
mWrongSensorObserved = false;
+
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
+ NUM_EVENT_MERCY_FACTOR = 0;
+ } else {
+ NUM_EVENT_MERCY_FACTOR = 0.3f;
+ }
}
/**
@@ -69,25 +84,79 @@
TestSensorEnvironment environment,
long testDurationUs) {
- long minTestDurationUs;
- long batchUs = environment.getMaxReportLatencyUs();
+ // The calculation is still OK if sampleUs is not the actual sensor hardware
+ // sample period since the actual sample period by definition only goes smaller, which
+ // result in more samples.
long sampleUs = environment.getExpectedSamplingPeriodUs();
- if (batchUs > 0) {
- // test duration deduct allowed delivering latency and portion of time to deliver batch
- // (which will be 10% of the batching time)
- long effectiveTime = testDurationUs - ALLOWED_SENSOR_DELIVERING_DELAY_US - batchUs/10;
- // allow part of last batch to be partially delivered (>80%)
- minTestDurationUs = Math.max(
- effectiveTime/batchUs * batchUs - batchUs/5,
- environment.getExpectedSamplingPeriodUs());
+ long askedBatchUs = environment.getMaxReportLatencyUs();
+
+ long reservedFifoUs = sampleUs * environment.getSensor().getFifoReservedEventCount(); //>=0
+
+ // max() prevent loop-hole if HAL specify smaller max fifo than reserved fifo.
+ long maximumFifoUs = Math.max(
+ sampleUs * environment.getSensor().getFifoMaxEventCount(), reservedFifoUs); //>=0
+
+ long effectiveDurationUs = Math.max(testDurationUs -
+ Math.max(ALLOWED_SENSOR_START_DELAY_US, environment.getAllowedSensorStartDelay()) -
+ ALLOWED_SENSOR_EVENT_LATENCY_US, 0);
+
+ boolean isSingleSensorTest = !environment.isIntegrationTest();
+
+ long expectedMinUs;
+ if (isSingleSensorTest) {
+ // When the sensor under test is the only one active, max fifo size is assumed to be
+ // available.
+ long expectedBatchUs = Math.min(maximumFifoUs, askedBatchUs);
+ if (expectedBatchUs > 0) {
+ // This sensor should be running in batching mode.
+ expectedMinUs =
+ effectiveDurationUs / expectedBatchUs * expectedBatchUs
+ - expectedBatchUs / 5;
+ } else {
+ // streaming, allow actual rate to be as slow as 80% of the asked rate.
+ expectedMinUs = effectiveDurationUs * 4 / 5;
+ }
} else {
- minTestDurationUs =
- Math.max(testDurationUs - ALLOWED_SENSOR_DELIVERING_DELAY_US,
- environment.getExpectedSamplingPeriodUs());
- }
+ // More convoluted case. Batch size can vary from reserved fifo length to max fifo size.
+ long minBatchUs = Math.min(reservedFifoUs, askedBatchUs);
+ long maxBatchUs = Math.min(maximumFifoUs, askedBatchUs);
- long expectedMinNumEvent = minTestDurationUs / environment.getExpectedSamplingPeriodUs();
+ // The worst scenario happens when the sensor batch time being just above half of the
+ // test time, then the test can only receive one batch which halves the expected number
+ // of samples. The expected number of samples received have a lower bound like the
+ // figure below.
+ //
+ // expected samples
+ // ^
+ // | ______
+ // |\ /
+ // | \ /
+ // | \ /
+ // | \ /
+ // | \ /
+ // | \ /
+ // | \/
+ // |
+ // |
+ // |
+ // |
+ // +------------+-----------+-------> actual batch size in time
+ // 0 1/2*testDuration testDuration
+ //
+ long worstBatchUs = effectiveDurationUs / 2 + 1;
+ if ((minBatchUs > worstBatchUs) == (maxBatchUs > worstBatchUs)) {
+ // same side
+ double ratio = Math.min(Math.abs(worstBatchUs - minBatchUs),
+ Math.abs(worstBatchUs - maxBatchUs)) / (double)worstBatchUs;
+ expectedMinUs = (long)((ratio + 1) / 2 * testDurationUs) * 4 / 5;
+ } else {
+ // the worst case is possible
+ expectedMinUs = worstBatchUs * 4 / 5;
+ }
+ }
+ long expectedMinNumEvent = expectedMinUs/sampleUs;
+
return new EventBasicVerification(expectedMinNumEvent, environment.getSensor());
}
@@ -103,7 +172,7 @@
stats.addValue(SensorStats.EVENT_COUNT_EXPECTED_KEY, mExpectedMinNumEvent);
stats.addValue(SensorStats.WRONG_SENSOR_KEY, mWrongSensorObserved);
- boolean enoughSample = mNumEvent >= mExpectedMinNumEvent;
+ boolean enoughSample = mNumEvent >= mExpectedMinNumEvent * ( 1 - NUM_EVENT_MERCY_FACTOR );
boolean noWrongSensor = !mWrongSensorObserved;
boolean success = enoughSample && noWrongSensor;
@@ -111,7 +180,8 @@
if (!success) {
Assert.fail(String.format("Failed due to (%s%s)",
- enoughSample?"":"insufficient events, ",
+ enoughSample?"":"insufficient events " + mNumEvent + "/" +
+ mExpectedMinNumEvent + ", ",
noWrongSensor?"":"wrong sensor observed, "));
}
}
diff --git a/tests/tests/hardware/src/android/hardware/fingerprint/cts/FingerprintManagerTest.java b/tests/tests/hardware/src/android/hardware/fingerprint/cts/FingerprintManagerTest.java
index 95704b9..f11b6bc 100644
--- a/tests/tests/hardware/src/android/hardware/fingerprint/cts/FingerprintManagerTest.java
+++ b/tests/tests/hardware/src/android/hardware/fingerprint/cts/FingerprintManagerTest.java
@@ -21,6 +21,7 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.os.CancellationSignal;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
/**
@@ -65,6 +66,7 @@
}
}
+ @Presubmit
public void test_hasFingerprintHardware() {
if (!mHasFingerprintManager) {
return; // skip test if no fingerprint feature
diff --git a/tests/tests/icu/AndroidTest.xml b/tests/tests/icu/AndroidTest.xml
index 299956d..18c95cd 100644
--- a/tests/tests/icu/AndroidTest.xml
+++ b/tests/tests/icu/AndroidTest.xml
@@ -20,5 +20,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="runner" value="android.icu.cts.IcuTestRunner" /><!-- override AJUR -->
<option name="package" value="android.icu.cts" />
+ <option name="runtime-hint" value="30m19s" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt b/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
index e667c08..9ca52c5 100644
--- a/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
+++ b/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
@@ -16,9 +16,9 @@
bug: "27310873"
},
{
- description: "Cannot find any classes to test because APK doesn't have entries for directories, android/icu/",
+ description: "Cannot find any classes to test because .class files are not treated as resources in APK",
name: "android.icu.dev.test.serializable.CoverageTest",
- bug: "27310873"
+ bug: "27666677"
},
{
description: "Serialized forms have not been converted to use repackaged classes",
@@ -34,42 +34,28 @@
description: "A completely empty test case",
name: "android.icu.dev.test.duration.PeriodBuilderTest"
},
-// The following are known to be broken but the reason is not yet known. They are expected to
-// succeed and so will be run and will fail but that is intentional so that they do not get
-// forgotten and are investigated to determine whether it is correct behavior on Android or a bug
-// that needs fixing.
{
- description: "Broken and not yet triaged",
- names: [
- "android.icu.dev.test.bidi.TestCompatibility#testCompatibility",
- "android.icu.dev.test.calendar.ChineseTest#TestCoverage",
- "android.icu.dev.test.calendar.ChineseTest#TestInitWithCurrentTime",
- "android.icu.dev.test.calendar.IBMCalendarTest#TestAddRollEra0AndEraBounds",
- "android.icu.dev.test.duration.ICUDurationTest#TestBasics",
- "android.icu.dev.test.format.DataDrivenFormatTest#TestConsistentPivot",
- "android.icu.dev.test.format.DataDrivenFormatTest#TestDateFormatBasic",
- "android.icu.dev.test.format.DateFormatRegressionTest#Test4073003",
- "android.icu.dev.test.format.DateFormatRegressionTest#Test4151706",
- "android.icu.dev.test.format.DateFormatRegressionTest#Test4182066",
- "android.icu.dev.test.format.DateFormatTest#TestBadInput135",
- "android.icu.dev.test.format.DateFormatTest#TestDotAndAtLeniency",
- "android.icu.dev.test.format.DateFormatTest#TestGenericTime",
- "android.icu.dev.test.format.DateFormatTest#TestPartialParse994",
- "android.icu.dev.test.format.DateFormatTest#TestQuarters",
- "android.icu.dev.test.format.DateFormatTest#TestSpaceParsing",
- "android.icu.dev.test.format.DateFormatTest#TestTwoDigitYear",
- "android.icu.dev.test.format.DateFormatTest#TestWhiteSpaceParsing",
- "android.icu.dev.test.format.NumberFormatTest#TestDataDrivenJDK",
- "android.icu.dev.test.format.NumberFormatTest#TestNonpositiveMultiplier",
- "android.icu.dev.test.format.PluralRulesTest#testOverUnderflow",
- "android.icu.dev.test.timezone.TimeZoneBoundaryTest#TestStepwise",
- "android.icu.dev.test.timezone.TimeZoneTest#TestObservesDaylightTime",
- "android.icu.dev.test.util.CurrencyTest#TestGetKeywordValues"
- ],
- result: "SUCCESS"
+ description: "Fails on host and on device in same way before and after packaging",
+ name: "android.icu.dev.test.bidi.TestCompatibility#testCompatibility",
+ bug: "23995372"
},
{
- description: "Broken due to warnings, not yet triaged",
+ description: "Problem with negative multiplier, not a regression",
+ name: "android.icu.dev.test.format.NumberFormatTest#TestNonpositiveMultiplier",
+ bug: "19185440"
+},
+{
+ description: "Wrong case for exponent separator",
+ name: "android.icu.dev.test.format.PluralRulesTest#testOverUnderflow",
+ bug: "27566754"
+},
+{
+ description: "Checks differences in DecimalFormat classes from ICU4J and JDK but on Android java.text.DecimalFormat is implemented in terms of ICU4J",
+ name: "android.icu.dev.test.format.NumberFormatTest#TestDataDrivenJDK",
+ bug: "27711713"
+},
+{
+ description: "Collation rules data has been removed from ICU4J data on Android",
names: [
"android.icu.dev.test.collator.CollationCreationMethodTest#TestRuleVsLocaleCreationMonkey",
"android.icu.dev.test.collator.CollationMiscTest#TestImport",
@@ -78,6 +64,6 @@
"android.icu.dev.test.collator.CollationTest#TestDataDriven",
"android.icu.dev.test.collator.G7CollationTest#TestG7Data"
],
- result: "SUCCESS"
+ bug: "27552651"
}
]
diff --git a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java b/tests/tests/icu/src/android/icu/cts/IcuRunListener.java
index 5e1e003..0a6f355 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java
+++ b/tests/tests/icu/src/android/icu/cts/IcuRunListener.java
@@ -17,12 +17,12 @@
package android.icu.cts;
import android.app.Instrumentation;
-import android.icu.cts.junit.ICUTestFailedException;
-import android.icu.cts.junit.IcuRunnerParams;
import android.os.Bundle;
+import android.support.test.internal.util.AndroidRunnerParams;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
+import junit.framework.AssertionFailedError;
import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
@@ -54,7 +54,7 @@
*/
private final Instrumentation instrumentation;
- private final IcuRunnerParams icuRunnerParams;
+ private final AndroidRunnerParams runnerParams;
private final int totalTestCount;
@@ -77,10 +77,10 @@
private long testStartTime;
- public IcuRunListener(Instrumentation instrumentation, IcuRunnerParams icuRunnerParams,
+ public IcuRunListener(Instrumentation instrumentation, AndroidRunnerParams runnerParams,
int totalTestCount) {
this.instrumentation = instrumentation;
- this.icuRunnerParams = icuRunnerParams;
+ this.runnerParams = runnerParams;
this.totalTestCount = totalTestCount;
failedTests = new ArrayList<>();
}
@@ -130,28 +130,15 @@
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
Throwable exception = failure.getException();
- if (exception instanceof ICUTestFailedException) {
- ICUTestFailedException icuTestFailedException =
- (ICUTestFailedException) exception;
-
- String information = icuTestFailedException.getInformation();
- int errorCount = icuTestFailedException.getErrorCount();
-
- // Include the detailed logs from ICU as the stack trace.
- currentTestResult.putString(REPORT_KEY_STACK, information);
-
- // Also append the logs to the console output.
- String output = "Failure: " + description + ", due to " + errorCount + " error(s)\n"
- + information;
- currentTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, output);
+ if (exception instanceof AssertionFailedError) {
resultStatus = REPORT_VALUE_RESULT_FAILURE;
} else {
- String information = failure.getTrace();
- currentTestResult.putString(REPORT_KEY_STACK, information);
- String output = "Error: " + description + "\n" + information;
- currentTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, output);
resultStatus = REPORT_VALUE_RESULT_ERROR;
}
+ String information = failure.getTrace();
+ currentTestResult.putString(REPORT_KEY_STACK, information);
+ String output = "Error: " + description + "\n" + information;
+ currentTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, output);
}
@Override
@@ -178,7 +165,7 @@
public Bundle getFinalResults() {
int totalTests = totalFailures + totalSuccess;
- Log.d(IcuTestRunner.TAG, (icuRunnerParams.getSkipExecution() ? "Skipped " : "Ran ")
+ Log.d(IcuTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
+ totalTests + " 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/tests/icu/src/android/icu/cts/IcuTestFilter.java
index 2ee1fcd..3da2976 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
+++ b/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
@@ -15,12 +15,13 @@
*/
package android.icu.cts;
-import android.icu.cts.junit.IcuTestFmwkRunner;
-import android.icu.cts.junit.IcuTestGroupRunner;
import android.util.Log;
+import java.util.List;
import javax.annotation.Nullable;
import org.junit.runner.Description;
import org.junit.runner.manipulation.Filter;
+import org.junit.runners.ParentRunner;
+import org.junit.runners.Suite;
import vogar.Expectation;
import vogar.ExpectationStore;
import vogar.Result;
@@ -28,36 +29,36 @@
/**
* Filter out tests/classes that are not requested or which are expected to fail.
*
- * <p>This filter has to handle a hierarchy of {@code Description descriptions} that looks
- * something like this (in CTSv2):
+ * <p>This filter has to handle both a hierarchy of {@code Description descriptions} that looks
+ * something like this:
* <pre>
- * IcuTestGroupRunner
- * IcuTestGroupRunner
- * IcuTestGroupRunner
- * IcuTestFmwkRunner
- * IcuFrameworkTest
+ * Suite
+ * Suite
+ * Suite
+ * ParentRunner
+ * Test
* ...
* ...
- * IcuTestFmwkRunner
- * IcuFrameworkTest
+ * ParentRunner
+ * Test
* ...
* ...
- * IcuTestGroupRunner
- * IcuTestFmwkRunner
- * IcuFrameworkTest
+ * Suite
+ * ParentRunner
+ * Test
* ...
* ...
* ...
* </pre>
*
* <p>And also a flatter hierarchy that looks like this (in CTSv1):
- * IcuTestFmwkRunner
- * IcuFrameworkTest
- * ...
+ * Runner
+ * Test
+ * ...
* ...
*
- * <p>It cannot filter out the non-leaf nodes in the hierarchy, i.e. {@link IcuTestGroupRunner} and
- * {@link IcuTestFmwkRunner}, as that would prevent it from traversing the hierarchy and finding
+ * <p>It cannot filter out the non-leaf nodes in the hierarchy, i.e. {@link Suite} and
+ * {@link ParentRunner}, as that would prevent it from traversing the hierarchy and finding
* the leaf nodes.
*/
class IcuTestFilter extends Filter {
@@ -73,12 +74,13 @@
@Override
public boolean shouldRun(Description description) {
- // The description will only have a method name if it is a leaf node in the hierarchy, see
- // class JavaDoc, otherwise it will be a non-leaf node. Non-leaf nodes must not be filtered
- // out as that would prevent leaf nodes from being visited.
- String methodName = description.getMethodName();
- if (methodName != null) {
- String className = description.getClassName();
+ // Only filter leaf nodes. The description is for a test if and only if it is a leaf node.
+ // Non-leaf nodes must not be filtered out as that would prevent leaf nodes from being
+ // visited in the case when we are traversing the hierarchy of classes.
+ Description testDescription = getTestDescription(description);
+ if (testDescription != null) {
+ String className = testDescription.getClassName();
+ String methodName = testDescription.getMethodName();
String testName = className + "#" + methodName;
// If the test isn't in the list of tests to run then do not run it.
@@ -99,6 +101,29 @@
return true;
}
+ private Description getTestDescription(Description description) {
+ List<Description> children = description.getChildren();
+ // An empty description is by definition a test.
+ if (children.isEmpty()) {
+ return description;
+ }
+
+ // Handle initialization errors that were wrapped in an ErrorReportingRunner as a special
+ // case. This is needed because ErrorReportingRunner is treated as a suite of Throwables,
+ // (where each Throwable corresponds to a test called initializationError) and so its
+ // description contains children, one for each Throwable, and so is not treated as a test
+ // to filter. Unfortunately, it does not support Filterable so this filter is never applied
+ // to its children.
+ // See https://github.com/junit-team/junit/issues/1253
+ Description child = children.get(0);
+ String methodName = child.getMethodName();
+ if ("initializationError".equals(methodName)) {
+ return child;
+ }
+
+ return null;
+ }
+
@Override
public String describe() {
return "IcuTestFilter";
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestList.java b/tests/tests/icu/src/android/icu/cts/IcuTestList.java
index c06b571..a9c3c5f 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestList.java
+++ b/tests/tests/icu/src/android/icu/cts/IcuTestList.java
@@ -15,7 +15,6 @@
*/
package android.icu.cts;
-import android.icu.cts.junit.TestFmwkUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.LinkedHashSet;
@@ -34,49 +33,59 @@
@Nullable
private final Set<String> testsToRun;
- private final List<Class> classesToRun;
+ private final List<Class<?>> classesToRun;
- /**
- * @param testNameList
- * The list of test names (i.e. {@code <class>#<method>}). If null then all
- * tests should be run.
- */
- public IcuTestList(@Nullable List<String> testNameList) {
+ public static IcuTestList exclusiveList(List<String> testNameList) {
+ Set<String> classNamesToRun = new LinkedHashSet<>();
+ Set<String> testsToRun = new LinkedHashSet<>(testNameList);
- // Populate a set with the unique class names of all the tests.
- Set<String> classNamesToRun;
- if (testNameList == null) {
- // Run from the root test class.
- classNamesToRun = TestFmwkUtils.getRootClassNames();
- Log.d(IcuTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
- testsToRun = null;
- } else {
- classNamesToRun = new LinkedHashSet<>();
- testsToRun = new LinkedHashSet<>(testNameList);
-
- for (String testName : testNameList) {
- int index = testName.indexOf('#');
- String className;
- if (index == -1) {
- className = testName;
- } else {
- className = testName.substring(0, index);
- }
- classNamesToRun.add(className);
+ for (String testName : testNameList) {
+ int index = testName.indexOf('#');
+ String className;
+ if (index == -1) {
+ className = testName;
+ } else {
+ className = testName.substring(0, index);
}
-
- Log.d(IcuTestRunner.TAG, "Running only the following tests: " + testsToRun);
+ classNamesToRun.add(className);
}
+ Log.d(IcuTestRunner.TAG, "Running only the following tests: " + testsToRun);
+ return new IcuTestList(getClasses(classNamesToRun), testsToRun);
+ }
+
+ public static IcuTestList 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);
+
+ List<Class<?>> classesToRun1 = getClasses(classNamesToRun);
+
+ return new IcuTestList(classesToRun1, null);
+ }
+
+ private static List<Class<?>> getClasses(Set<String> classNames) {
// Populate the list of classes to run.
- classesToRun = new ArrayList<>();
- for (String className : classNamesToRun) {
+ List<Class<?>> classesToRun = new ArrayList<>();
+ for (String className : classNames) {
try {
classesToRun.add(Class.forName(className));
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Could not load class '" + className, e);
}
}
+ return classesToRun;
+ }
+
+ /**
+ * @param classes The list of classes to run.
+ * @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) {
+ this.testsToRun = testsToRun;
+ this.classesToRun = classes;
}
/**
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java b/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
index 48a4cc1..51c4999 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
+++ b/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
@@ -18,10 +18,10 @@
import android.app.Activity;
import android.app.Instrumentation;
-import android.icu.cts.junit.IcuRunnerParams;
-import android.icu.cts.junit.IcuTestRunnerBuilder;
+import android.icu.junit.IcuTestRunnerBuilder;
import android.os.Bundle;
import android.os.Debug;
+import android.support.test.internal.util.AndroidRunnerParams;
import android.util.Log;
import java.io.BufferedReader;
import java.io.FileReader;
@@ -62,6 +62,9 @@
private static final List<String> EXPECTATIONS_PATHS =
Collections.singletonList("expectations/icu-known-failures.txt");
+ /** The args for the runner. */
+ private Bundle args;
+
/** Only count the number of tests, and not run them. */
private boolean testCountOnly;
@@ -82,8 +85,9 @@
@Override
public void onCreate(Bundle args) {
super.onCreate(args);
+ this.args = args;
- boolean debug = args.getBoolean(ARGUMENT_DEBUG);
+ boolean debug = "true".equalsIgnoreCase(args.getString(ARGUMENT_DEBUG));
if (debug) {
Log.i(TAG, "Waiting for debugger to connect...");
Debug.waitForDebugger();
@@ -126,28 +130,34 @@
testNameList = null;
}
- icuTestList = new IcuTestList(testNameList);
+ if (testNameList == null) {
+ icuTestList = IcuTestList.rootList(Arrays.asList(
+ "android.icu.cts.coverage.TestAll",
+ "android.icu.dev.test.TestAll"));
+ } else {
+ icuTestList = IcuTestList.exclusiveList(testNameList);
+ }
start();
}
@Override
public void onStart() {
-
if (logOnly || testCountOnly) {
Log.d(TAG, "Counting/logging tests only");
} else {
Log.d(TAG, "Running tests");
}
- IcuRunnerParams icuRunnerParams = new IcuRunnerParams(logOnly || testCountOnly);
+ AndroidRunnerParams runnerParams = new AndroidRunnerParams(this, args,
+ logOnly || testCountOnly, -1, false);
JUnitCore core = new JUnitCore();
Request request;
int totalTestCount;
try {
- RunnerBuilder runnerBuilder = new IcuTestRunnerBuilder(icuRunnerParams);
+ RunnerBuilder runnerBuilder = new IcuTestRunnerBuilder(runnerParams);
Class[] classes = icuTestList.getClassesToRun();
Runner suite = new Computer().getSuite(runnerBuilder, classes);
@@ -173,7 +183,7 @@
throw new RuntimeException("Could not create a suite", e);
}
- IcuRunListener icuRunListener = new IcuRunListener(this, icuRunnerParams, totalTestCount);
+ IcuRunListener icuRunListener = new IcuRunListener(this, runnerParams, totalTestCount);
core.addListener(icuRunListener);
core.run(request);
diff --git a/tests/tests/icu/src/android/icu/cts/junit/ErrorReportingRunner.java b/tests/tests/icu/src/android/icu/cts/junit/ErrorReportingRunner.java
deleted file mode 100644
index bbd0651..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/ErrorReportingRunner.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package android.icu.cts.junit;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.junit.runner.Description;
-import org.junit.runner.Runner;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.Filterable;
-import org.junit.runner.manipulation.NoTestsRemainException;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.InitializationError;
-
-/**
- * A copy of the JUnit 4.10 {@link org.junit.internal.runners.ErrorReportingRunner} class.
- *
- * <p>Modified as follows:</p>
- *
- * <ul>
- * <li>allows the class in error to be specified by name rather than {@link Class} object so that it
- * can be used for when the class could not be found. See
- * {@link #ErrorReportingRunner(String, Throwable)} and
- * {@link #fTestClassName}.
- * <li>supports filtering of the individual causes. See {@link #filter(Filter)}.
- * <li>uses the cause to construct the description allowing filtering on specific error messages.
- * See {@link #describeCause(Throwable)}.
- * </ul>
- */
-// android-changed - implements Filterable
-class ErrorReportingRunner extends Runner implements Filterable {
- private final List<Throwable> fCauses;
-
- // android-changed - changed type from Class<?> and renamed from fTestClass.
- private final String fTestClassName;
-
- public ErrorReportingRunner(String testClassName, Throwable cause) {
- fTestClassName = testClassName;
- // Take a copy so that they can be modified during filtering if necessary.
- fCauses = new ArrayList<>(getCauses(cause));
- }
- // end android-changed
-
- @Override
- public Description getDescription() {
- // android-changed - renamed from fTestClass.
- Description description= Description.createSuiteDescription(fTestClassName);
- // end android-changed
- for (Throwable each : fCauses)
- description.addChild(describeCause(each));
- return description;
- }
-
- @Override
- public void run(RunNotifier notifier) {
- for (Throwable each : fCauses)
- runCause(each, notifier);
- }
-
- // android-changed - added filtering support
- @Override
- public void filter(Filter filter) throws NoTestsRemainException {
- Iterator<Throwable> iterator = fCauses.iterator();
- while (iterator.hasNext()) {
- Throwable cause = iterator.next();
- Description description = describeCause(cause);
- if (!filter.shouldRun(description)) {
- iterator.remove();
- }
- }
-
- // If there are no causes left then throw an exception to cause the parent runner, if any,
- // to remove this runner from its list.
- if (fCauses.isEmpty()) {
- throw new NoTestsRemainException();
- }
- }
- // end android-changed
-
- @SuppressWarnings("deprecation")
- private List<Throwable> getCauses(Throwable cause) {
- if (cause instanceof InvocationTargetException)
- return getCauses(cause.getCause());
- if (cause instanceof InitializationError)
- return ((InitializationError) cause).getCauses();
- if (cause instanceof org.junit.internal.runners.InitializationError)
- return ((org.junit.internal.runners.InitializationError) cause)
- .getCauses();
- return Arrays.asList(cause);
- }
-
- private Description describeCause(Throwable child) {
- // android-changed - create a description that incorporates the cause
- // Extract the first line of the message, exclude any special characters that could
- // cause problems with later parsing of the description.
- String message = child.getMessage();
- Matcher matcher = Pattern.compile("^([^()\n]*).*").matcher(message);
- if (matcher.matches()) {
- message = matcher.group(1);
- }
-
- // Create a suite description (need to use that method because the createTestDescription
- // methods use a class rather than a class name).
- String causeClassName = child.getClass().getName();
- return Description.createSuiteDescription(
- String.format("initializationError[%s: %s](%s)",
- causeClassName, message, fTestClassName));
- // end android-changed
- }
-
- private void runCause(Throwable child, RunNotifier notifier) {
- Description description= describeCause(child);
- notifier.fireTestStarted(description);
- notifier.fireTestFailure(new Failure(description, child));
- notifier.fireTestFinished(description);
- }
-}
\ No newline at end of file
diff --git a/tests/tests/icu/src/android/icu/cts/junit/ICUTestFailedException.java b/tests/tests/icu/src/android/icu/cts/junit/ICUTestFailedException.java
deleted file mode 100644
index 0e9f045..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/ICUTestFailedException.java
+++ /dev/null
@@ -1,51 +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.icu.cts.junit;
-
-/**
- * An exception used to tunnel extra failure information from a failing test to
- * {@link android.icu.cts.IcuRunListener}
- */
-public class ICUTestFailedException extends Exception {
-
- /**
- * The number of errors found within the test.
- *
- * <p>The ICU test framework differs from JUnit as an individual test can continue after an
- * error is encountered, this field keeps track of the number of errors encountered.
- */
- private final int errorCount;
-
- /**
- * The output from the test itself.
- */
- private final String information;
-
- public ICUTestFailedException(String message, int errorCount, String information) {
- super(message);
- this.errorCount = errorCount;
- this.information = information;
- }
-
- public int getErrorCount() {
- return errorCount;
- }
-
- public String getInformation() {
- return information;
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/IcuFrameworkTest.java b/tests/tests/icu/src/android/icu/cts/junit/IcuFrameworkTest.java
deleted file mode 100644
index 7e85497..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/IcuFrameworkTest.java
+++ /dev/null
@@ -1,128 +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.icu.cts.junit;
-
-import android.icu.dev.test.TestFmwk;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.junit.runner.Description;
-
-/**
- * Represents a test within a {@link TestFmwk} class.
- */
-final class IcuFrameworkTest implements Comparable<IcuFrameworkTest> {
-
- private static final String[] EMPTY_ARGS = new String[0];
-
- private static final Pattern EXTRACT_ERROR_INFO = Pattern.compile(
- "^[A-Za-z0-9_]+ \\{(\n.*)\n\\}.*", Pattern.DOTALL);
-
- /**
- * The {@link TestFmwk} instance on which the tests will be run.
- */
- private final TestFmwk testFmwk;
-
- private final TestFmwk.Target target;
-
- /**
- * The name of the individual target to run.
- */
- private final String methodName;
-
- IcuFrameworkTest(TestFmwk testFmwk, TestFmwk.Target target, String methodName) {
- this.testFmwk = testFmwk;
- this.target = target;
- this.methodName = methodName;
- }
-
- public String getMethodName() {
- return methodName;
- }
-
- /**
- * Runs the target.
- */
- public void run() throws ICUTestFailedException {
- test_for_TestFmwk_Run();
- }
-
- /**
- * A special method to avoid the TestFmwk from throwing an InternalError when an error occurs
- * during execution of the test but outside the actual test method, e.g. in a
- * {@link TestFmwk#validate()} method. See http://bugs.icu-project.org/trac/ticket/12183
- *
- * <p>DO NOT CHANGE THE NAME
- */
- private void test_for_TestFmwk_Run() throws ICUTestFailedException {
- StringWriter stringWriter = new StringWriter();
- PrintWriter log = new PrintWriter(stringWriter);
-
- TestFmwk.TestParams localParams = TestFmwk.TestParams.create(EMPTY_ARGS, log);
- if (localParams == null) {
- throw new IllegalStateException("Could not create params");
- }
-
- // We don't want an error summary as we are only running one test.
- localParams.errorSummary = null;
-
- try {
- // Make sure that the TestFmwk is initialized with the correct parameters. This method
- // is being called solely for its side effect of updating the TestFmwk.params field.
- testFmwk.resolveTarget(localParams);
-
- // Run the target.
- target.run();
- } catch (Exception e) {
- // Output the exception to the log and make sure it is treated as an error.
- e.printStackTrace(log);
- localParams.errorCount++;
- }
-
- // Treat warnings as errors.
- int errorCount = localParams.errorCount + localParams.warnCount;
-
- // Ensure that all data is written to the StringWriter.
- log.flush();
-
- // Treat warnings as errors.
- String information = stringWriter.toString();
- if (errorCount != 0) {
- // Remove unnecessary formatting.
- Matcher matcher = EXTRACT_ERROR_INFO.matcher(information);
- if (matcher.matches()) {
- information = matcher.group(1)/*.replace("\n ", "\n")*/;
- }
- throw new ICUTestFailedException("ICU test failed: " + getDescription(),
- errorCount, information);
- }
- }
-
- /**
- * Get the JUnit {@link Description}
- */
- public Description getDescription() {
- // Get a description for the specific method within the class.
- return Description.createTestDescription(testFmwk.getClass(), methodName);
- }
-
- @Override
- public int compareTo(IcuFrameworkTest o) {
- return methodName.compareTo(o.methodName);
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/IcuRunnerParams.java b/tests/tests/icu/src/android/icu/cts/junit/IcuRunnerParams.java
deleted file mode 100644
index 369b672..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/IcuRunnerParams.java
+++ /dev/null
@@ -1,40 +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.icu.cts.junit;
-
-/**
- * Encapsulates options passed to {@link IcuTestFmwkRunner}.
- */
-public class IcuRunnerParams {
-
- /**
- * True if the tests should not actually be executed, false otherwise.
- */
- private final boolean skipExecution;
-
- public static IcuRunnerParams getDefaultParams() {
- return new IcuRunnerParams(false);
- }
-
- public IcuRunnerParams(boolean skipExecution) {
- this.skipExecution = skipExecution;
- }
-
- public boolean getSkipExecution() {
- return skipExecution;
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/IcuTestFmwkRunner.java b/tests/tests/icu/src/android/icu/cts/junit/IcuTestFmwkRunner.java
deleted file mode 100644
index a290ae6..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/IcuTestFmwkRunner.java
+++ /dev/null
@@ -1,131 +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.icu.cts.junit;
-
-import android.icu.dev.test.TestFmwk;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import org.junit.runner.Description;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.Statement;
-
-/**
- * A {@link org.junit.runner.Runner} that can be used to run a class that is a {@link TestFmwk}
- * but not a {@link android.icu.dev.test.TestFmwk.TestGroup}
- */
-public class IcuTestFmwkRunner extends IcuTestParentRunner<IcuFrameworkTest> {
-
- /**
- * A {@link Statement} that does nothing, used when skipping execution.
- */
- private static final Statement EMPTY_STATEMENT = new Statement() {
- @Override
- public void evaluate() throws Throwable {
- }
- };
-
- private final IcuRunnerParams icuRunnerParams;
-
- private final List<IcuFrameworkTest> tests;
-
- /**
- * The constructor used when this class is used with {@code @RunWith(...)}.
- */
- public IcuTestFmwkRunner(Class<?> testClass)
- throws Exception {
- this(checkClass(testClass), IcuRunnerParams.getDefaultParams());
- }
-
- /**
- * Make sure that the supplied test class is supported by this.
- */
- private static Class<? extends TestFmwk> checkClass(Class<?> testClass) {
- if (!TestFmwk.class.isAssignableFrom(testClass)) {
- throw new IllegalStateException(
- "Cannot use " + IcuTestFmwkRunner.class + " for running "
- + testClass + " as it is not a " + TestFmwk.class);
- }
- if (TestFmwk.TestGroup.class.isAssignableFrom(testClass)) {
- throw new IllegalStateException(
- "Cannot use " + IcuTestFmwkRunner.class + " for running "
- + testClass + " as it is a " + TestFmwk.TestGroup.class
- + ": Use @RunWith(" + IcuTestGroupRunner.class.getSimpleName()
- + ".class) instead");
- }
-
- return testClass.asSubclass(TestFmwk.class);
- }
-
- IcuTestFmwkRunner(Class<? extends TestFmwk> testFmwkClass, IcuRunnerParams icuRunnerParams)
- throws Exception {
- super(testFmwkClass);
-
- this.icuRunnerParams = icuRunnerParams;
-
- // Create a TestFmwk and make sure that it's initialized properly.
- TestFmwk testFmwk = TestFmwkUtils.newTestFmwkInstance(testFmwkClass);
-
- tests = new ArrayList<>();
-
- TestFmwk.Target target = TestFmwkUtils.getTargets(testFmwk);
- while (target != null) {
- String name = target.name;
- // Just ignore targets that do not have a name, they are do nothing place holders.
- if (name != null) {
- tests.add(new IcuFrameworkTest(testFmwk, target, name));
- }
- target = target.getNext();
- }
-
- // If the class has no tests then fail.
- if (tests.isEmpty()) {
- throw new IllegalStateException("Cannot find any tests for " + testFmwkClass);
- }
-
- // Sort the methods to ensure consistent ordering.
- Collections.sort(tests);
- }
-
- @Override
- protected List<IcuFrameworkTest> getChildren() {
- return tests;
- }
-
- @Override
- protected Description describeChild(IcuFrameworkTest child) {
- return child.getDescription();
- }
-
- @Override
- protected void runChild(final IcuFrameworkTest child, RunNotifier notifier) {
- Description description = describeChild(child);
- Statement statement;
- if (icuRunnerParams.getSkipExecution()) {
- statement = EMPTY_STATEMENT;
- } else {
- statement = new Statement() {
- @Override
- public void evaluate() throws Throwable {
- child.run();
- }
- };
- }
- runLeaf(statement, description, notifier);
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/IcuTestGroupRunner.java b/tests/tests/icu/src/android/icu/cts/junit/IcuTestGroupRunner.java
deleted file mode 100644
index b09de71..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/IcuTestGroupRunner.java
+++ /dev/null
@@ -1,98 +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.icu.cts.junit;
-
-import android.icu.dev.test.TestFmwk;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.runner.Description;
-import org.junit.runner.Runner;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.RunnerBuilder;
-
-/**
- * A {@link org.junit.runner.Runner} that can be used to run a class that is a
- * {@link TestFmwk.TestGroup} but not a {@link TestFmwk}
- */
-public class IcuTestGroupRunner extends IcuTestParentRunner<Runner> {
-
- private final List<Runner> runners;
-
- /**
- * The constructor used when this class is used with {@code @RunWith(...)}.
- */
- public IcuTestGroupRunner(Class<?> testClass, RunnerBuilder runnerBuilder)
- throws Exception {
- super(testClass);
-
- Class<? extends TestFmwk.TestGroup> testGroupClass = checkClass(testClass);
-
- // Create a TestGroup and make sure that it's initialized properly.
- TestFmwk.TestGroup testGroup = TestFmwkUtils.newTestFmwkInstance(testGroupClass);
-
- runners = new ArrayList<>();
- List<String> classNames = TestFmwkUtils.getClassNames(testGroup);
- ClassLoader classLoader = testGroupClass.getClassLoader();
- for (String className : classNames) {
- Runner runner;
-
- try {
- Class<?> childTestClass = Class.forName(className, false, classLoader);
- runner = runnerBuilder.safeRunnerForClass(childTestClass);
- } catch (ClassNotFoundException e) {
- runner = new ErrorReportingRunner(className, e);
- }
-
- runners.add(runner);
- }
- }
-
- /**
- * Make sure that the supplied test class is supported by this.
- */
- private static Class<? extends TestFmwk.TestGroup> checkClass(Class<?> testClass) {
- if (!TestFmwk.TestGroup.class.isAssignableFrom(testClass)) {
- if (TestFmwk.class.isAssignableFrom(testClass)) {
- throw new IllegalStateException(
- "Cannot use " + IcuTestGroupRunner.class + " for running "
- + testClass + " as it is a " + TestFmwk.class
- + ": Use @RunWith(" + IcuTestFmwkRunner.class.getSimpleName()
- + ".class) instead");
- }
- throw new IllegalStateException(
- "Cannot use " + IcuTestGroupRunner.class + " for running "
- + testClass + " as it is not a " + TestFmwk.TestGroup.class);
- }
-
- return testClass.asSubclass(TestFmwk.TestGroup.class);
- }
-
- @Override
- protected List<Runner> getChildren() {
- return runners;
- }
-
- @Override
- protected Description describeChild(Runner child) {
- return child.getDescription();
- }
-
- @Override
- protected void runChild(Runner child, RunNotifier notifier) {
- child.run(notifier);
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/IcuTestParentRunner.java b/tests/tests/icu/src/android/icu/cts/junit/IcuTestParentRunner.java
deleted file mode 100644
index 8bf05b9..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/IcuTestParentRunner.java
+++ /dev/null
@@ -1,55 +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.icu.cts.junit;
-
-import org.junit.runners.ParentRunner;
-import org.junit.runners.model.InitializationError;
-
-/**
- * Extends {@link ParentRunner} to prevent it from trying to create an instance of
- * {@link org.junit.runners.model.TestClass} for the supplied {@code testClass} because that
- * requires that the {@code testClass} has only a single constructor and at least one ICU test
- * ({@code android.icu.dev.test.serializable.CoverageTest}) has more than one constructor.
- *
- * <p>This provides a dummy class and overrides the {@link #getName()} method to return the
- * correct name. The consequence of this is that it is not possible to use JUnit 4 annotations
- * related to the class, like {@link org.junit.BeforeClass}, {@link org.junit.ClassRule}, etc.
- */
-abstract class IcuTestParentRunner<T> extends ParentRunner<T> {
-
- private final Class<?> testClass;
-
- IcuTestParentRunner(Class<?> testClass) throws InitializationError {
- super(DummyTestClass.class);
- this.testClass = testClass;
- }
-
- @Override
- protected String getName() {
- return testClass.getName();
- }
-
- /**
- * A dummy test class to pass to {@link ParentRunner} for it to validate and check for
- * annotations.
- *
- * <p>Must be public.
- */
- public static class DummyTestClass {
-
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/IcuTestRunnerBuilder.java b/tests/tests/icu/src/android/icu/cts/junit/IcuTestRunnerBuilder.java
deleted file mode 100644
index 16b915c..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/IcuTestRunnerBuilder.java
+++ /dev/null
@@ -1,52 +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.icu.cts.junit;
-
-import android.icu.dev.test.TestFmwk;
-import org.junit.runner.Runner;
-import org.junit.runners.model.RunnerBuilder;
-
-/**
- * A {@link RunnerBuilder} used for running ICU test classes derived from {@link TestFmwk}.
- */
-public class IcuTestRunnerBuilder extends RunnerBuilder {
-
- private final IcuRunnerParams icuRunnerParams;
-
- public IcuTestRunnerBuilder(IcuRunnerParams icuRunnerParams) {
- this.icuRunnerParams = icuRunnerParams;
- }
-
- @Override
- public Runner runnerForClass(Class<?> testClass) throws Throwable {
- try {
- // Check for a TestGroup before a TestFmwk class as TestGroup is a subclass of TestFmwk
- if (TestFmwk.TestGroup.class.isAssignableFrom(testClass)) {
- return new IcuTestGroupRunner(testClass.asSubclass(TestFmwk.TestGroup.class), this);
- }
-
- if (TestFmwk.class.isAssignableFrom(testClass)) {
- // Make sure that in the event of an error the resulting Runner an be filtered out.
- return new IcuTestFmwkRunner(testClass.asSubclass(TestFmwk.class), icuRunnerParams);
- }
- } catch (Exception e) {
- return new ErrorReportingRunner(testClass.getName(), e);
- }
-
- return null;
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/TestFmwkUtils.java b/tests/tests/icu/src/android/icu/cts/junit/TestFmwkUtils.java
deleted file mode 100644
index 1ddf86d..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/TestFmwkUtils.java
+++ /dev/null
@@ -1,160 +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.icu.cts.junit;
-
-import android.icu.dev.test.TestFmwk;
-import com.google.common.collect.ImmutableSet;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Abstracts away reflection code that accesses various hidden fields and methods in the ICU test
- * framework.
- *
- * <p>Assuming that this is integrated into ICU test framework itself then ideally the test
- * framework will itself be modified to remove the need for this reflection at which point this
- * class can be removed.
- */
-public class TestFmwkUtils {
-
- /**
- * The field on TestGroup which has the list of classes in it.
- */
- private static final Field classesToTestField = getField(TestFmwk.TestGroup.class, "names");
-
- /**
- * The field on TestGroup which has the default package in it.
- */
- private static final Field defaultPackageField =
- getField(TestFmwk.TestGroup.class, "defaultPackage");
-
- /**
- * The field on TestFmwk which has the {@link android.icu.dev.test.TestFmwk.TestParams} in it.
- */
- private static final Field paramsField = getField(TestFmwk.class, "params");
-
- private static final Method getTargetsMethod = getTargetsMethod();
-
- private static final String REPACKAGED_ROOT_TEST_GROUP_NAME = "android.icu.dev.test.TestAll";
-
- private static Field getField(Class<?> theClass, String name) {
- // Find the field, and complain if it is not where it's expected to be.
- try {
- Field field = theClass.getDeclaredField(name);
- field.setAccessible(true); // It's private by default.
- return field;
- } catch (NoSuchFieldException e) {
- throw new RuntimeException("Class structure of ICU tests have changed.", e);
- }
- }
-
- private static Method getTargetsMethod() {
- try {
- Method method = TestFmwk.class.getDeclaredMethod("getTargets", String.class);
- method.setAccessible(true);
- return method;
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Class structure of ICU tests have changed.", e);
- }
- }
-
- public static TestFmwk.Target getTargets(TestFmwk testFmwk) {
- return test_for_TestFmwk_GetTargets(testFmwk);
- }
-
- /**
- * A special method to avoid the TestFmwk from throwing an InternalError when an error occurs
- * during execution of the test but outside the actual test method, e.g. in a
- * {@link TestFmwk#validate()} method. See http://bugs.icu-project.org/trac/ticket/12183
- *
- * <p>DO NOT CHANGE THE NAME
- */
- private static TestFmwk.Target test_for_TestFmwk_GetTargets(TestFmwk testFmwk) {
- try {
- return (TestFmwk.Target) getTargetsMethod.invoke(testFmwk, new Object[] {null});
- } catch (InvocationTargetException | IllegalAccessException e) {
- throw new IllegalStateException(
- "Problem calling getTargets(null) on " + testFmwk, e);
- }
- }
-
- public static <T extends TestFmwk> T newTestFmwkInstance(Class<? extends T> testFmwkClass)
- throws IllegalAccessException, InstantiationException {
- // Create a TestFmwk and make sure that it's params field is initialized.
- T testFmwk = testFmwkClass.newInstance();
- TestFmwk.TestParams testParams = TestFmwk.TestParams.create(new String[0], null);
- paramsField.set(testFmwk, testParams);
- return testFmwk;
- }
-
- private static boolean hasGetTargetsMethod(Class<?> clazz) {
- try {
- clazz.getDeclaredMethod("getTargets", String.class);
- return true;
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- public static boolean overridesGetTargetsMethod(Class<?> testFmwkClass) {
- while (testFmwkClass != TestFmwk.class && testFmwkClass != Object.class) {
- if (hasGetTargetsMethod(testFmwkClass)) {
- return true;
- }
-
- testFmwkClass = testFmwkClass.getSuperclass();
- }
-
- return false;
- }
-
- public static List<String> getClassNames(TestFmwk.TestGroup testGroup) {
- try {
- String[] classNames = (String[]) classesToTestField.get(testGroup);
- String defaultPackage = (String) defaultPackageField.get(testGroup);
-
- List<String> list = new ArrayList<>(classNames.length);
- for (String basicName : classNames) {
- // Handle relative class names.
- String fullyQualifiedName;
- if (basicName.contains(".")) {
- fullyQualifiedName = basicName;
- } else {
- fullyQualifiedName = defaultPackage + basicName;
- }
-
- list.add(fullyQualifiedName);
- }
-
- // Sort to ensure consistent ordering.
- Collections.sort(list);
-
- return list;
- } catch (IllegalAccessException e) {
- throw new IllegalStateException("Problem getting class names from " + testGroup, e);
- }
- }
-
- public static Set<String> getRootClassNames() {
- return ImmutableSet.of(REPACKAGED_ROOT_TEST_GROUP_NAME);
- }
-}
diff --git a/tests/tests/icu/src/android/icu/cts/junit/package-info.java b/tests/tests/icu/src/android/icu/cts/junit/package-info.java
deleted file mode 100644
index 2da0748..0000000
--- a/tests/tests/icu/src/android/icu/cts/junit/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * Contains classes used to make ICU tests runnable by JUnit.
- *
- * <p>Ideally, this will be integrated into ICU itself and cleaned up so that ICU tests can be
- * simply run using standard JUnit. e.g. ICU test classes will be annotated with
- * {@code RunWith(IcuTestGroupRunner.class)} or {@code RunWith(IcuTestFmwkRunner.class)} depending
- * on whether they extend {@link android.icu.dev.test.TestFmwk.TestGroup} or
- * {@link android.icu.dev.test.TestFmwk}.
- */
-package android.icu.cts.junit;
diff --git a/tests/tests/icu/test-list.txt b/tests/tests/icu/test-list.txt
index 93b9f89..84da3c4 100644
--- a/tests/tests/icu/test-list.txt
+++ b/tests/tests/icu/test-list.txt
@@ -3,7 +3,6 @@
android.icu.dev.test.bidi.TestBidi#testBidi
android.icu.dev.test.bidi.TestCharFromDirProp#testCharFromDirProp
android.icu.dev.test.bidi.TestClassOverride#testClassOverride
-android.icu.dev.test.bidi.TestCompatibility#testCompatibility
android.icu.dev.test.bidi.TestContext#testContext
android.icu.dev.test.bidi.TestFailureRecovery#testFailureRecovery
android.icu.dev.test.bidi.TestInverse#testInverse
@@ -267,7 +266,6 @@
android.icu.dev.test.collator.CollationAPITest#TestSubClass
android.icu.dev.test.collator.CollationAPITest#TestVariableTopSetting
android.icu.dev.test.collator.CollationChineseTest#TestPinYin
-android.icu.dev.test.collator.CollationCreationMethodTest#TestRuleVsLocaleCreationMonkey
android.icu.dev.test.collator.CollationCurrencyTest#TestCurrency
android.icu.dev.test.collator.CollationDummyTest#TestExtra
android.icu.dev.test.collator.CollationDummyTest#TestIdentical
@@ -341,8 +339,6 @@
android.icu.dev.test.collator.CollationMiscTest#TestHungarianTailoring
android.icu.dev.test.collator.CollationMiscTest#TestIdenticalCompare
android.icu.dev.test.collator.CollationMiscTest#TestImplicitTailoring
-android.icu.dev.test.collator.CollationMiscTest#TestImport
-android.icu.dev.test.collator.CollationMiscTest#TestImportWithType
android.icu.dev.test.collator.CollationMiscTest#TestIncompleteCnt
android.icu.dev.test.collator.CollationMiscTest#TestIncrementalNormalize
android.icu.dev.test.collator.CollationMiscTest#TestInvalidListsAndRanges
@@ -384,7 +380,6 @@
android.icu.dev.test.collator.CollationMiscTest#TestSurrogates
android.icu.dev.test.collator.CollationMiscTest#TestTibetanConformance
android.icu.dev.test.collator.CollationMiscTest#TestUCAPrecontext
-android.icu.dev.test.collator.CollationMiscTest#TestUCARules
android.icu.dev.test.collator.CollationMiscTest#TestUnknownCollationKeyword
android.icu.dev.test.collator.CollationMiscTest#TestUpperFirstQuaternary
android.icu.dev.test.collator.CollationMiscTest#TestVariableTop
@@ -442,7 +437,6 @@
android.icu.dev.test.collator.CollationSpanishTest#TestPrimary
android.icu.dev.test.collator.CollationSpanishTest#TestTertiary
android.icu.dev.test.collator.CollationTest#TestCollationWeights
-android.icu.dev.test.collator.CollationTest#TestDataDriven
android.icu.dev.test.collator.CollationTest#TestFCD
android.icu.dev.test.collator.CollationTest#TestImplicits
android.icu.dev.test.collator.CollationTest#TestMinMax
@@ -462,7 +456,6 @@
android.icu.dev.test.collator.G7CollationTest#TestDemo2
android.icu.dev.test.collator.G7CollationTest#TestDemo3
android.icu.dev.test.collator.G7CollationTest#TestDemo4
-android.icu.dev.test.collator.G7CollationTest#TestG7Data
android.icu.dev.test.collator.LotusCollationKoreanTest#TestTertiary
android.icu.dev.test.collator.UCAConformanceTest#TestRulesNonIgnorable
android.icu.dev.test.collator.UCAConformanceTest#TestRulesShifted
@@ -965,7 +958,6 @@
android.icu.dev.test.format.NumberFormatTest#TestCurrFmtNegSameAsPositive
android.icu.dev.test.format.NumberFormatTest#TestCustomCurrencySignAndSeparator
android.icu.dev.test.format.NumberFormatTest#TestDataDrivenICU
-android.icu.dev.test.format.NumberFormatTest#TestDataDrivenJDK
android.icu.dev.test.format.NumberFormatTest#TestDecimalFormatCurrencyParse
android.icu.dev.test.format.NumberFormatTest#TestExplicitParents
android.icu.dev.test.format.NumberFormatTest#TestExponent
@@ -989,7 +981,6 @@
android.icu.dev.test.format.NumberFormatTest#TestMiscCurrencyParsing
android.icu.dev.test.format.NumberFormatTest#TestMultiCurrencySign
android.icu.dev.test.format.NumberFormatTest#TestNegZeroRounding
-android.icu.dev.test.format.NumberFormatTest#TestNonpositiveMultiplier
android.icu.dev.test.format.NumberFormatTest#TestNumberFormatFactory
android.icu.dev.test.format.NumberFormatTest#TestNumberFormatTestTupleToString
android.icu.dev.test.format.NumberFormatTest#TestNumberingSystems
@@ -1140,7 +1131,6 @@
android.icu.dev.test.format.PluralRulesTest#TestLocales
android.icu.dev.test.format.PluralRulesTest#testOperands
android.icu.dev.test.format.PluralRulesTest#TestOrdinal
-android.icu.dev.test.format.PluralRulesTest#testOverUnderflow
android.icu.dev.test.format.PluralRulesTest#TestParseDescription
android.icu.dev.test.format.PluralRulesTest#testParseEmpty
android.icu.dev.test.format.PluralRulesTest#testParsing
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index 7ba87e3..8e86c0e 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -23,7 +23,8 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner core-tests-support
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctstestrunner core-tests-support platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index 60a48e0..57a7648 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -16,6 +16,7 @@
package android.keystore.cts;
+import android.platform.test.annotations.Presubmit;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.test.AndroidTestCase;
@@ -221,6 +222,7 @@
private static final byte[] AES256_KAT_KEY_BYTES =
HexEncoding.decode("cf601cc10aaf434d1f01747136aff222af7fb426d101901712214c3fea18125f");
+ @Presubmit
public void testAlgorithmList() {
// Assert that Android Keystore Provider exposes exactly the expected Cipher
// transformations. We don't care whether the transformations are exposed via aliases, as
diff --git a/tests/tests/location/AndroidTest.xml b/tests/tests/location/AndroidTest.xml
index 178e8d1..4ac850e 100644
--- a/tests/tests/location/AndroidTest.xml
+++ b/tests/tests/location/AndroidTest.xml
@@ -21,7 +21,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.location.cts" />
- <option name="runtime-hint" value="1m26s" />
+ <option name="runtime-hint" value="18m8s" />
</test>
</configuration>
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
index ce81402..3ae7b3c 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
@@ -51,7 +51,6 @@
measurement.setState(14);
measurement.setSvid(15);
measurement.setTimeOffsetNanos(16.0);
- measurement.setPseudorangeRateCorrected(true);
}
private static void verifyTestValues(GnssMeasurement measurement) {
@@ -74,7 +73,6 @@
assertEquals(14, measurement.getState());
assertEquals(15, measurement.getSvid());
assertEquals(16.0, measurement.getTimeOffsetNanos());
- assertTrue(measurement.isPseudorangeRateCorrected());
}
public void testWriteToParcel() {
@@ -95,11 +93,6 @@
verifyTestValues(newMeasurement);
}
- public void testPseudorangeRateCorrected() {
- GnssMeasurement measurement = new GnssMeasurement();
- measurement.isPseudorangeRateCorrected();
- }
-
public void testSetReset() {
GnssMeasurement measurement = new GnssMeasurement();
setTestValues(measurement);
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
index 930c344..72addce 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
@@ -16,6 +16,8 @@
package android.location.cts;
+import android.location.GnssClock;
+import android.location.GnssMeasurement;
import android.location.GnssMeasurementsEvent;
import android.test.AndroidTestCase;
@@ -25,7 +27,11 @@
public void testAllMethodsExist() {
GnssMeasurementsEvent.Callback callback = new MockCallback();
- GnssMeasurementsEvent event = new GnssMeasurementsEvent(null, null);
+ GnssClock clock = new GnssClock();
+ GnssMeasurement m1 = new GnssMeasurement();
+ GnssMeasurement m2 = new GnssMeasurement();
+ GnssMeasurementsEvent event = new GnssMeasurementsEvent(
+ clock, new GnssMeasurement[] {m1, m2});
callback.onGnssMeasurementsReceived(event);
callback.onStatusChanged(GnssMeasurementsEvent.STATUS_READY);
}
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
index 33cf924..51af03d 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
@@ -28,7 +28,11 @@
public class GnssMeasurementsEventTest extends AndroidTestCase {
public void testDescribeContents() {
- GnssMeasurementsEvent event = new GnssMeasurementsEvent(null, null);
+ GnssClock clock = new GnssClock();
+ GnssMeasurement m1 = new GnssMeasurement();
+ GnssMeasurement m2 = new GnssMeasurement();
+ GnssMeasurementsEvent event = new GnssMeasurementsEvent(
+ clock, new GnssMeasurement[] {m1, m2});
event.describeContents();
}
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
index a548122..0589c57 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
@@ -16,6 +16,7 @@
package android.location.cts;
+import android.location.GnssNavigationMessage;
import android.location.GnssNavigationMessageEvent;
import android.test.AndroidTestCase;
@@ -25,7 +26,8 @@
public void testAllMethodsExist() {
GnssNavigationMessageEvent.Callback callback = new MockCallback();
- GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(null);
+ GnssNavigationMessage message = new GnssNavigationMessage();
+ GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
callback.onGnssNavigationMessageReceived(event);
callback.onStatusChanged(GnssNavigationMessageEvent.STATUS_READY);
}
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
index 730bd525..0772092 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
@@ -23,7 +23,8 @@
public class GnssNavigationMessageEventTest extends AndroidTestCase {
public void testDescribeContents() {
- GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(null);
+ GnssNavigationMessage message = new GnssNavigationMessage();
+ GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
event.describeContents();
}
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
index 87814c5..a4e18e6 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
@@ -93,7 +93,7 @@
private static void setTestValues(GnssNavigationMessage message) {
message.setData(new byte[] {1, 2, 3, 4});
message.setMessageId(5);
- message.setStatus(GnssNavigationMessage.PARCELABLE_WRITE_RETURN_VALUE);
+ message.setStatus(GnssNavigationMessage.STATUS_PARITY_REBUILT);
message.setSubmessageId(6);
message.setSvid(7);
message.setType(GnssNavigationMessage.TYPE_GPS_L2CNAV);
@@ -101,12 +101,13 @@
private static void verifyTestValues(GnssNavigationMessage message) {
byte[] data = message.getData();
+ assertEquals(4, data.length);
assertEquals(1, data[0]);
assertEquals(2, data[1]);
assertEquals(3, data[2]);
assertEquals(4, data[3]);
assertEquals(5, message.getMessageId());
- assertEquals(GnssNavigationMessage.PARCELABLE_WRITE_RETURN_VALUE, message.getStatus());
+ assertEquals(GnssNavigationMessage.STATUS_PARITY_REBUILT, message.getStatus());
assertEquals(6, message.getSubmessageId());
assertEquals(7, message.getSvid());
assertEquals(GnssNavigationMessage.TYPE_GPS_L2CNAV, message.getType());
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index 85de83d..36358ab 100644
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -477,7 +477,7 @@
}
try {
- mManager.removeUpdates( (LocationListener) null );
+ mManager.removeUpdates((LocationListener) null );
fail("Should throw IllegalArgumentException if listener is null!");
} catch (IllegalArgumentException e) {
// expected
@@ -566,7 +566,12 @@
updateLocation(latitude3, longitude3);
assertFalse(listener.hasCalledOnLocationChanged(TEST_TIME_OUT));
- mManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, mPendingIntent);
+ try {
+ mManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, mPendingIntent);
+ fail("Should throw IllegalArgumentException if PendingIntent is null!");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
try {
mManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, (LocationListener) null,
@@ -584,7 +589,7 @@
}
try {
- mManager.removeUpdates( (LocationListener) null );
+ mManager.removeUpdates((LocationListener) null );
fail("Should throw IllegalArgumentException if listener is null!");
} catch (IllegalArgumentException e) {
// expected
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 7a92a2c..879c72b 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -44,9 +44,9 @@
# include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner ndkaudio
-LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libaudio_jni libnativehelper_compat_libc++
+LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libaudio_jni libnativehelper_compat_libc++ libndkaudioLib
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/media/libaudiojni/Android.mk b/tests/tests/media/libaudiojni/Android.mk
index 27b42c1..d1b1ced 100644
--- a/tests/tests/media/libaudiojni/Android.mk
+++ b/tests/tests/media/libaudiojni/Android.mk
@@ -37,4 +37,6 @@
LOCAL_SHARED_LIBRARIES := libandroid liblog libnativehelper_compat_libc++ libOpenSLES
LOCAL_CXX_STL := libc++_static
+LOCAL_CFLAGS := -Werror -Wall
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libaudiojni/appendix-b-1-2-recording.cpp b/tests/tests/media/libaudiojni/appendix-b-1-2-recording.cpp
index 5f6f3aa..e628c6f 100644
--- a/tests/tests/media/libaudiojni/appendix-b-1-2-recording.cpp
+++ b/tests/tests/media/libaudiojni/appendix-b-1-2-recording.cpp
@@ -56,8 +56,6 @@
SLDataLocator_IODevice locator_mic;
SLDeviceVolumeItf devicevolumeItf;
SLDataSink audioSink;
- SLDataLocator_URI uri;
- SLDataFormat_MIME mime;
int i;
SLboolean required[MAX_NUMBER_INTERFACES];
diff --git a/tests/tests/media/libaudiojni/audio-record-native.cpp b/tests/tests/media/libaudiojni/audio-record-native.cpp
index 5f72ab3..f771d9b 100644
--- a/tests/tests/media/libaudiojni/audio-record-native.cpp
+++ b/tests/tests/media/libaudiojni/audio-record-native.cpp
@@ -405,7 +405,6 @@
}
static void BufferQueueCallback(SLBufferQueueItf queueItf, void *pContext) {
- SLresult res;
// naked native record
AudioRecordNative *record = (AudioRecordNative *)pContext;
record->bufferQueueCallback(queueItf);
diff --git a/tests/tests/media/libaudiojni/audio-track-native.cpp b/tests/tests/media/libaudiojni/audio-track-native.cpp
index 23e6a0f..ce8bf91 100644
--- a/tests/tests/media/libaudiojni/audio-track-native.cpp
+++ b/tests/tests/media/libaudiojni/audio-track-native.cpp
@@ -345,7 +345,6 @@
}
static void BufferQueueCallback(SLBufferQueueItf queueItf, void *pContext) {
- SLresult res;
// naked native track
AudioTrackNative *track = (AudioTrackNative *)pContext;
track->bufferQueueCallback(queueItf);
diff --git a/tests/tests/media/libmediandkjni/Android.mk b/tests/tests/media/libmediandkjni/Android.mk
index b59d1fb..259c95e 100644
--- a/tests/tests/media/libmediandkjni/Android.mk
+++ b/tests/tests/media/libmediandkjni/Android.mk
@@ -35,4 +35,6 @@
LOCAL_SDK_VERSION := 23
+LOCAL_CFLAGS := -Werror -Wall
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index f15a196..546ef2b 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -263,7 +263,7 @@
int t = AMediaExtractor_getSampleTrackIndex(ex);
if (t >=0) {
ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
- ALOGV("track %d, input buffer %d", t, bufidx);
+ ALOGV("track %d, input buffer %zd", t, bufidx);
if (bufidx >= 0) {
size_t bufsize;
uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
@@ -408,7 +408,7 @@
while (!sawOutputEOS) {
ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
- ALOGV("input buffer %d", bufidx);
+ ALOGV("input buffer %zd", bufidx);
if (bufidx >= 0) {
size_t bufsize;
uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
@@ -481,7 +481,7 @@
return false;
} else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
ssize_t tidx = AMediaMuxer_addTrack(muxer, format);
- ALOGI("track %d -> %d format %s", i, tidx, s);
+ ALOGI("track %d -> %zd format %s", i, tidx, s);
AMediaExtractor_selectTrack(ex, i);
} else {
ALOGE("expected audio or video mime type, got %s", mime);
@@ -536,7 +536,7 @@
int64_t duration = 0;
if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration)
|| duration != 123456789123456789ll) {
- ALOGE("AMediaFormat_getInt64 fail: %lld", duration);
+ ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration);
return false;
}
diff --git a/tests/tests/media/libndkaudio/Android.mk b/tests/tests/media/libndkaudio/Android.mk
new file mode 100644
index 0000000..29e2118
--- /dev/null
+++ b/tests/tests/media/libndkaudio/Android.mk
@@ -0,0 +1,59 @@
+# 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_MODULE := libndkaudioLib
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+ frameworks/wilhelm/include \
+ frameworks/wilhelm/src/android \
+ $(call include-path-for, wilhelm)
+
+LOCAL_SRC_FILES := \
+ OpenSLESUtils.cpp \
+ AudioPlayer.cpp \
+ AudioSource.cpp \
+ PeriodicAudioSource.cpp \
+ SystemParams.cpp \
+ WaveTableGenerator.cpp \
+ WaveTableOscillator.cpp \
+ com_android_ndkaudio_AudioPlayer.cpp \
+ AudioRecorder.cpp \
+ com_android_ndkaudio_AudioRecorder.cpp
+
+LOCAL_CXX_STL := libc++_static
+
+LOCAL_SHARED_LIBRARIES := liblog libOpenSLES
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# ndkaudio - java
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := ndkaudio
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/media/libndkaudio/AndroidManifest.xml b/tests/tests/media/libndkaudio/AndroidManifest.xml
new file mode 100644
index 0000000..3fbb9ad
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AndroidManifest.xml
@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ndkaudio"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="23"
+ android:targetSdkVersion="23" />
+
+</manifest>
diff --git a/tests/tests/media/libndkaudio/AudioPlayer.cpp b/tests/tests/media/libndkaudio/AudioPlayer.cpp
new file mode 100644
index 0000000..af7d24a
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioPlayer.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+
+#include <android/log.h>
+
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+
+#include "AudioPlayer.h"
+
+#include "AudioSource.h"
+#include "SystemParams.h"
+#include "OpenSLESUtils.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * OpenSL ES Stuff
+ */
+static const char* TAG = "AudioPlayer";
+
+// engine interfaces
+static SLObjectItf engineObject = 0;
+static SLEngineItf engineItf;
+
+// output mix interfaces
+static SLObjectItf outputMixObject = 0;
+
+// this callback handler is called every time a buffer finishes playing
+static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf /*bq*/, void *context)
+{
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "bqPlayerCallback()");
+ ((ndkaudio::AudioPlayer*)context)->enqueBuffer();
+}
+
+static void OpenSLEngine() {
+ SLresult result;
+
+ // create engine
+ result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "OpenSLEngine() - engineObject:%p", engineObject);
+
+ // realize the engine
+ result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Realize() engine result:%s", getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ // get the engine interface, which is needed in order to create other objects
+ result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineItf);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "GetInterface() engine:%p result:%s", engineItf, getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ // get the output mixer
+ result = (*engineItf)->CreateOutputMix(engineItf, &outputMixObject, 0, 0, 0);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "CreateOutputMix() mix:%p result:%s", outputMixObject, getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ // realize the output mix
+ result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Realize() result:%s", getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+}
+
+static void CloseSLEngine() {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "CloseSLEngine()");
+
+ // destroy output mix object, and invalidate all associated interfaces
+ if (outputMixObject != NULL) {
+ (*outputMixObject)->Destroy(outputMixObject);
+ outputMixObject = NULL;
+ }
+
+ if (engineObject != NULL) {
+ (*engineObject)->Destroy(engineObject);
+ engineObject = NULL;
+ engineItf = NULL;
+ }
+}
+
+/*
+ * AudioPlayer
+ */
+namespace ndkaudio {
+
+AudioPlayer::AudioPlayer() {
+ source_ = NULL;
+
+ sampleRate_ = SystemParams::getSampleRate();
+ numChannels_ = 1;
+
+ numPlayBuffFrames_ = SystemParams::getNumBufferFrames();
+
+ playing_ = false;
+
+ time_ = 0;
+
+ bqPlayerObject_ = NULL;
+ bq_ = NULL;
+ bqPlayerPlay_ = NULL;
+ configItf_ = NULL;
+
+ OpenSLEngine();
+}
+
+AudioPlayer::~AudioPlayer() {
+ CloseSLEngine();
+
+ delete[] playBuff_;
+ playBuff_ = 0;
+}
+
+SLresult AudioPlayer::Open(int numChannels, AudioSource* source) {
+ source_ = source;
+
+ SLresult result;
+
+ numChannels_ = numChannels;
+
+ int internalBuffFactor = 1;
+
+ playBuff_ =
+ new float[numPlayBuffFrames_ * numChannels_ * internalBuffFactor];
+ playBuffSizeInBytes_ = numPlayBuffFrames_ * numChannels_ * sizeof(float)
+ * internalBuffFactor;
+
+ sampleRate_ = SystemParams::getSampleRate();
+
+// __android_log_print(ANDROID_LOG_INFO, TAG,
+// "AudioPlayer::Open(chans:%d, rate:%d)", numChannels,
+// sampleRate_);
+
+ // configure audio source
+ SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType
+ 1}; // numBuffers
+
+ // SLuint32 chanMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
+ SLAndroidDataFormat_PCM_EX format_pcm = {SL_ANDROID_DATAFORMAT_PCM_EX, // formatType
+ (SLuint32) numChannels_, // numChannels
+ (SLuint32)(sampleRate_ * 1000), // milliSamplesPerSec
+ 32, // bitsPerSample
+ 32, // containerSize;
+ (SLuint32) chanCountToChanMask(numChannels_), // channelMask
+ SL_BYTEORDER_LITTLEENDIAN, // endianness
+ SL_ANDROID_PCM_REPRESENTATION_FLOAT}; // representation
+ SLDataSource audioSrc = {&loc_bufq, &format_pcm};
+
+ // configure audio sink
+ SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX,
+ outputMixObject};
+ SLDataSink audioSnk = {&loc_outmix, NULL};
+
+ const SLInterfaceID ids[] =
+ {SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION};
+ const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+
+ // The Player
+ result = (*engineItf)->CreateAudioPlayer(engineItf, &bqPlayerObject_,
+ &audioSrc, &audioSnk,
+ sizeof(ids) / sizeof(ids[0]), ids,
+ req);
+// __android_log_print(ANDROID_LOG_INFO, TAG,
+// "CreateAudioPlayer() result:%s, bqPlayerObject_:%p",
+// getSLErrStr(result), bqPlayerObject_);
+ assert(SL_RESULT_SUCCESS == result);
+
+ return result;
+}
+
+void AudioPlayer::Close() {
+ __android_log_write(ANDROID_LOG_INFO, TAG, "CloseSLPlayer()");
+
+ if (bqPlayerObject_ != NULL) {
+ (*bqPlayerObject_)->Destroy(bqPlayerObject_);
+ bqPlayerObject_ = NULL;
+
+ // invalidate any interfaces
+ bqPlayerPlay_ = NULL;
+ bq_ = NULL;
+ }
+}
+
+SLresult AudioPlayer::RealizePlayer() {
+ SLresult result;
+
+ result = (*bqPlayerObject_)->Realize(bqPlayerObject_, SL_BOOLEAN_FALSE);
+// __android_log_print(ANDROID_LOG_INFO, TAG,
+// "Realize player object result:%s", getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_PLAY,
+ &bqPlayerPlay_);
+// __android_log_print(ANDROID_LOG_INFO, TAG,
+// "get player interface result:%s, bqPlayerPlay_:%p",
+// getSLErrStr(result), bqPlayerPlay_);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // The BufferQueue
+ result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_,
+ SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+ &bq_);
+// __android_log_print(ANDROID_LOG_INFO, TAG,
+// "get bufferqueue interface:%p result:%s", bq_,
+// getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ // The register BufferQueue callback
+ result = (*bq_)->RegisterCallback(bq_, bqPlayerCallback, this);
+// __android_log_print(ANDROID_LOG_INFO, TAG, "register callback result:%s",
+// getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ return result;
+}
+
+SLresult AudioPlayer::RealizeRoutingProxy() {
+ SLresult result;
+
+ // The Config interface (for routing)
+ result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_,
+ SL_IID_ANDROIDCONFIGURATION,
+ (void*) &configItf_);
+// __android_log_print(ANDROID_LOG_INFO, TAG, "get Config result:%s",
+// getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ return result;
+}
+
+SLresult AudioPlayer::Start() {
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Start()");
+ playing_ = true;
+
+ // set the player's state to playing
+ SLresult result = (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_,
+ SL_PLAYSTATE_PLAYING);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SetPlayState() result:%s", getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+
+ enqueBuffer();
+
+ return result;
+}
+
+void AudioPlayer::Stop() {
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Stop()");
+ playing_ = false;
+}
+
+SLresult AudioPlayer::enqueBuffer() {
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer::enqueBuffer()");
+ if (playing_) {
+ //long dataSizeInSamples = source_->getData(time_++, playBuff_,
+ // numPlayBuffFrames_,
+ // source_->getNumChannels());
+ return (*bq_)->Enqueue(bq_, playBuff_, playBuffSizeInBytes_);
+ } else {
+ (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_, SL_PLAYSTATE_STOPPED);
+ return 0;
+ }
+}
+
+} // namespace ndkaudio
+
diff --git a/tests/tests/media/libndkaudio/AudioPlayer.h b/tests/tests/media/libndkaudio/AudioPlayer.h
new file mode 100644
index 0000000..57d48c7
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioPlayer.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef AUDIOPLAYER_H_
+#define AUDIOPLAYER_H_
+
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+
+namespace ndkaudio {
+
+class AudioSource;
+
+class AudioPlayer {
+ public:
+ AudioPlayer();
+ ~AudioPlayer();
+
+ SLresult Open(int numChannels, AudioSource* filler);
+ void Close();
+
+ SLresult RealizePlayer();
+ SLresult RealizeRoutingProxy();
+
+ SLresult Start();
+ void Stop();
+
+ inline bool isPlaying() {
+ return playing_;
+ }
+ inline AudioSource* getSource() {
+ return source_;
+ }
+
+ // This is public because it needs to be called by the OpenSL ES callback, but it should not
+ // be called by anyone else.
+ SLresult enqueBuffer();
+
+ SLPlayItf getPlayerObject() {
+ return bqPlayerPlay_;
+ }
+
+ SLAndroidConfigurationItf getConfigItf() {
+ return configItf_;
+ }
+
+ private:
+ // void fill();
+
+ AudioSource* source_;
+ int sampleRate_;
+ int numChannels_;
+
+ float* playBuff_;
+ long numPlayBuffFrames_;
+ long playBuffSizeInBytes_;
+
+ bool playing_;
+
+ long time_;
+
+ // OpenSLES stuff
+ SLObjectItf bqPlayerObject_;
+ SLPlayItf bqPlayerPlay_;
+ SLAndroidSimpleBufferQueueItf bq_;
+ SLAndroidConfigurationItf configItf_;
+};
+
+} // namespace ndkaudio
+
+#endif /* AUDIOPLAYER_H_ */
diff --git a/tests/tests/media/libndkaudio/AudioRecorder.cpp b/tests/tests/media/libndkaudio/AudioRecorder.cpp
new file mode 100644
index 0000000..050c29d
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioRecorder.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+#include <assert.h>
+
+#include <android/log.h>
+
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+
+#include "AudioRecorder.h"
+
+#include "AudioSink.h"
+#include "SystemParams.h"
+#include "OpenSLESUtils.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define ARRAYSIZE(a) sizeof((a))/sizeof((a)[0])
+
+using namespace ndkaudio;
+
+//static const char* const TAG = "AudioRecorder";
+
+#define NB_BUFFERS_IN_QUEUE 1
+
+static void RecCallback(SLRecordItf /*recorderItf_*/, void * /*context*/, SLuint32 event)
+{
+ if (SL_RECORDEVENT_HEADATNEWPOS & event) {
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SL_RECORDEVENT_HEADATNEWPOS");
+ }
+
+ if (SL_RECORDEVENT_HEADATMARKER & event) {
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SL_RECORDEVENT_HEADATMARKER");
+ }
+
+ if (SL_RECORDEVENT_BUFFER_FULL & event) {
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SL_RECORDEVENT_BUFFER_FULL");
+ }
+}
+
+#define BUFFER_SIZE_IN_FRAMES 8192
+
+static float* recBuffer = NULL;
+
+static void RecBufferQueueCallback(SLAndroidSimpleBufferQueueItf /*queueItf*/, void * context)
+{
+ AudioRecorder* recorder = (AudioRecorder*)context;
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "RecBufferQueueCallback()");
+ recorder->enqueBuffer();
+}
+
+/*
+ * The OpenSL ES code was derived from:
+ * frameworks/wilhelm/tests/examples/slesTestRecBuffQueue.cpp
+ */
+AudioRecorder::AudioRecorder()
+ : sink_(NULL),
+ recording_(false),
+ sampleRate_(48000),
+ numChannels_(0),
+ numBufferSamples_(0),
+ engineObj_(NULL),
+ engineItf_(NULL),
+ recorderObj_(NULL),
+ recorderItf_(NULL),
+ recBuffQueueItf_(NULL),
+ configItf_(NULL)
+{}
+
+AudioRecorder::~AudioRecorder() {}
+
+void AudioRecorder::Open(int numChannels, AudioSink* sink) {
+ sink_ = sink;
+ numChannels_ = numChannels;
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "AudioRecorder::Open() - numChannels:%d", numChannels);
+
+ SLresult result;
+
+ numBufferSamples_ = BUFFER_SIZE_IN_FRAMES * numChannels_;
+ recBuffer = new float[numBufferSamples_];
+
+ SLEngineOption EngineOption[] = {
+ {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
+ };
+
+ /* Create the OpenSL ES Engine object */
+ result = slCreateEngine(&engineObj_, 1, EngineOption, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "slCreateEngine() - engineObj_:%p", engineObj_);
+
+ /* Realizing the SL Engine in synchronous mode. */
+ result = (*engineObj_)->Realize(engineObj_, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "(*engineObj_)->Realize()");
+
+ result = (*engineObj_)->GetInterface(engineObj_, SL_IID_ENGINE, (void*)&engineItf_);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "GetInterface() - engineItf_:%p", engineItf_);
+
+ // Configuration of the recorder
+ SLboolean required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+ SLInterfaceID iidArray[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION};
+
+ SLDataLocator_IODevice ioDevice;
+ ioDevice.locatorType = SL_DATALOCATOR_IODEVICE;
+ ioDevice.deviceType = SL_IODEVICE_AUDIOINPUT;
+ ioDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
+ ioDevice.device = NULL;
+
+ SLDataSource recSource;
+ recSource.pLocator = (void *) &ioDevice;
+ recSource.pFormat = NULL;
+
+ /* Setup the (OpenSL ES) data sink */
+ SLDataLocator_AndroidSimpleBufferQueue recBuffQueue;
+ recBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
+ recBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE;
+
+ SLAndroidDataFormat_PCM_EX pcm;
+ pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
+ pcm.numChannels = numChannels_;
+ pcm.sampleRate = sampleRate_ * 1000; // milliHz
+ pcm.bitsPerSample = 32;
+ pcm.containerSize = 32;
+ pcm.channelMask = chanCountToChanMask(numChannels_);
+ pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
+ pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
+
+ SLDataSink recDest;
+ recDest.pLocator = (void *) &recBuffQueue;
+ recDest.pFormat = (void * ) &pcm;
+
+ /* Create the audio recorder */
+ result = (*engineItf_)->CreateAudioRecorder(engineItf_, &recorderObj_, &recSource, &recDest,
+ ARRAYSIZE(iidArray), iidArray, required);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "CreateAudioRecorder() - recorderObj_:%p", recorderObj_);
+}
+
+void AudioRecorder::Close() {
+ /* Shutdown OpenSL ES */
+ (*engineObj_)->Destroy(engineObj_);
+ engineObj_ = 0;
+}
+
+void AudioRecorder::RealizeRecorder() {
+ SLresult result;
+
+ /* Realize the recorder in synchronous mode. */
+ result = (*recorderObj_)->Realize(recorderObj_, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Recorder realized");
+
+ /* Get the record interface which is implicit */
+ result = (*recorderObj_)->GetInterface(recorderObj_, SL_IID_RECORD, (void*)&recorderItf_);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "GetInterface() recorderItf_:%p", recorderItf_);
+
+ /* Set up the recorder callback to get events during the recording */
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SetMarkerPosition()");
+ result = (*recorderItf_)->SetMarkerPosition(recorderItf_, 2000);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SetPositionUpdatePeriod()");
+ result = (*recorderItf_)->SetPositionUpdatePeriod(recorderItf_, 500);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "SetCallbackEventsMask()");
+ result = (*recorderItf_)->SetCallbackEventsMask(recorderItf_, SL_RECORDEVENT_HEADATMARKER | SL_RECORDEVENT_HEADATNEWPOS);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "RegisterCallback() - Events");
+ result = (*recorderItf_)->RegisterCallback(recorderItf_, RecCallback, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+
+ /* Get the buffer queue interface which was explicitly requested */
+ result = (*recorderObj_)->GetInterface(recorderObj_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void*)&recBuffQueueItf_);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "GetInterface() recBuffQueueItf_:%p", recBuffQueueItf_);
+
+ result = (*recBuffQueueItf_)->RegisterCallback(recBuffQueueItf_, RecBufferQueueCallback, (void*)this);
+ assert(SL_RESULT_SUCCESS == result);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "RegisterCallback() - Buffers");
+}
+
+void AudioRecorder::RealizeRoutingProxy() {
+ SLresult result;
+ // The Config interface (for routing)
+ result = (*recorderObj_)->GetInterface(recorderObj_, SL_IID_ANDROIDCONFIGURATION, (void*)&configItf_);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "get Config result:%s", getSLErrStr(result));
+ assert(SL_RESULT_SUCCESS == result);
+}
+
+void AudioRecorder::Start() {
+ SLresult result;
+
+ /* Enqueue buffers to map the region of memory allocated to store the recorded data */
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Enqueueing buffer");
+ //int bufferSizeInBytes = BUFFER_SIZE_IN_FRAMES * numChannels_ * sizeof(float);
+
+ enqueBuffer();
+
+ /* ------------------------------------------------------ */
+ /* Start recording */
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Start Recording");
+ recording_ = true;
+ result = (*recorderItf_)->SetRecordState(recorderItf_, SL_RECORDSTATE_RECORDING);
+ assert(SL_RESULT_SUCCESS == result);
+}
+
+void AudioRecorder::Stop() {
+ recording_ = false;
+
+ SLresult result;
+ result = (*recorderItf_)->SetRecordState(recorderItf_, SL_RECORDSTATE_STOPPED);
+}
+
+SLresult AudioRecorder::enqueBuffer() {
+ SLresult result;
+ int bufferSizeInBytes = numBufferSamples_ * sizeof(float);
+ // __android_log_print(ANDROID_LOG_INFO, TAG, "Enque %d bytes", bufferSizeInBytes);
+ result = (*recBuffQueueItf_)->Enqueue(recBuffQueueItf_, recBuffer, bufferSizeInBytes);
+ assert(SL_RESULT_SUCCESS == result);
+
+ return result;
+}
+
+float* AudioRecorder::GetRecordBuffer() {
+ return recBuffer;
+}
diff --git a/tests/tests/media/libndkaudio/AudioRecorder.h b/tests/tests/media/libndkaudio/AudioRecorder.h
new file mode 100644
index 0000000..93a03c3
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioRecorder.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef _AUDIORECORDER_H_
+#define _AUDIORECORDER_H_
+
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+
+namespace ndkaudio {
+
+class AudioSink;
+
+class AudioRecorder {
+ public:
+ AudioRecorder();
+ ~AudioRecorder();
+
+ void Open(int numChannels, AudioSink* sink);
+ void Close();
+
+ void RealizeRecorder();
+ void RealizeRoutingProxy();
+
+ void Start();
+ void Stop();
+
+ inline bool isRecording() {
+ return recording_;
+ }
+ inline AudioSink* getSink() {
+ return sink_;
+ }
+
+ SLAndroidConfigurationItf getConfigItf() {
+ return configItf_;
+ }
+
+ // public, but don't call directly (called by the OSLES callback)
+ SLresult enqueBuffer();
+
+ int GetNumBufferSamples() {
+ return numBufferSamples_;
+ }
+ float* GetRecordBuffer();
+
+ private:
+ AudioSink* sink_;
+ bool recording_;
+
+ int sampleRate_;
+ int numChannels_;
+
+ int numBufferSamples_;
+
+ // OpenSL ES stuff
+ // - Engine
+ SLObjectItf engineObj_;
+ SLEngineItf engineItf_;
+
+ // - Recorder
+ SLObjectItf recorderObj_;
+ SLRecordItf recorderItf_;
+ SLAndroidSimpleBufferQueueItf recBuffQueueItf_;
+ SLAndroidConfigurationItf configItf_;
+};
+
+} // namespace ndkaudio
+
+#endif // _AUDIORECORDER_H_
diff --git a/tests/tests/media/libndkaudio/AudioSink.h b/tests/tests/media/libndkaudio/AudioSink.h
new file mode 100644
index 0000000..933abc9
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioSink.h
@@ -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.
+ */
+
+#ifndef _AUDIOSINK_H_
+#define _AUDIOSINK_H_
+
+namespace ndkaudio {
+
+class AudioSink {
+ public:
+ AudioSink();
+ virtual ~AudioSink();
+
+ virtual bool put(float * buff, int numFrames, int numChannels) =0;
+};
+
+} // namespace ndkaudio
+
+#endif // _AUDIOSINK_H_
+
diff --git a/tests/tests/media/libndkaudio/AudioSource.cpp b/tests/tests/media/libndkaudio/AudioSource.cpp
new file mode 100644
index 0000000..6e4fbbc
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioSource.cpp
@@ -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.
+ */
+
+#include "AudioSource.h"
+
+#include "SystemParams.h"
+
+namespace ndkaudio {
+
+//static const char* const TAG = "AudioSource";
+
+AudioSource::AudioSource(int numChannels)
+ : numChannels_(numChannels),
+ lastReadSize_(0),
+ numBuffFrames_(SystemParams::getNumBufferFrames())
+{}
+
+AudioSource::~AudioSource()
+{}
+
+} // namespace ndkaudio
diff --git a/tests/tests/media/libndkaudio/AudioSource.h b/tests/tests/media/libndkaudio/AudioSource.h
new file mode 100644
index 0000000..1d192b4
--- /dev/null
+++ b/tests/tests/media/libndkaudio/AudioSource.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef AUDIOSOURCE_H_
+#define AUDIOSOURCE_H_
+
+namespace ndkaudio {
+
+class AudioSource {
+ public:
+ AudioSource(int numChannels);
+ virtual ~AudioSource();
+
+ int getLastReadSize() {
+ return lastReadSize_;
+ }
+ int getNumChannels() {
+ return numChannels_;
+ }
+ int getNumBufferFrames() {
+ return numBuffFrames_;
+ }
+
+ virtual int getData(long time, float * buff, int numFrames,
+ int numChannels) =0;
+
+ protected:
+ int numChannels_;
+ int lastReadSize_;
+ int numBuffFrames_;
+};
+
+} //namespace ndkaudio
+
+#endif /* AUDIOSOURCE_H_ */
diff --git a/tests/tests/media/libndkaudio/OpenSLESUtils.cpp b/tests/tests/media/libndkaudio/OpenSLESUtils.cpp
new file mode 100644
index 0000000..7302ef5
--- /dev/null
+++ b/tests/tests/media/libndkaudio/OpenSLESUtils.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include "OpenSLESUtils.h"
+
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+
+/*
+ * OSLES Helpers
+ */
+static const char* errStrings[] = {
+ "SL_RESULT_SUCCESS", // 0)
+ "SL_RESULT_PRECONDITIONS_VIOLATE", // 1
+ "SL_RESULT_PARAMETER_INVALID", // 2
+ "SL_RESULT_MEMORY_FAILURE", // 3
+ "SL_RESULT_RESOURCE_ERROR", // 4
+ "SL_RESULT_RESOURCE_LOST", // 5
+ "SL_RESULT_IO_ERROR", // 6
+ "SL_RESULT_BUFFER_INSUFFICIENT", // 7
+ "SL_RESULT_CONTENT_CORRUPTED", // 8
+ "SL_RESULT_CONTENT_UNSUPPORTED", // 9
+ "SL_RESULT_CONTENT_NOT_FOUND", // 10
+ "SL_RESULT_PERMISSION_DENIED", // 11
+ "SL_RESULT_FEATURE_UNSUPPORTED", // 12
+ "SL_RESULT_INTERNAL_ERROR", // 13
+ "SL_RESULT_UNKNOWN_ERROR", // 14
+ "SL_RESULT_OPERATION_ABORTED", // 15
+ "SL_RESULT_CONTROL_LOST" // 16
+};
+
+const char * getSLErrStr(int code) {
+ return errStrings[code];
+}
+
+// These will wind up in <SLES/OpenSLES_Android.h>
+#define SL_ANDROID_SPEAKER_QUAD (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \
+ | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
+
+#define SL_ANDROID_SPEAKER_5DOT1 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \
+ | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT \
+ | SL_SPEAKER_BACK_RIGHT)
+
+#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT \
+ |SL_SPEAKER_SIDE_RIGHT)
+
+int chanCountToChanMask(int chanCount) {
+ int channelMask = 0;
+
+ switch (chanCount) {
+ case 1:
+ channelMask = SL_SPEAKER_FRONT_CENTER;
+ break;
+
+ case 2:
+ channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+ break;
+
+ case 4: // Quad
+ channelMask = SL_ANDROID_SPEAKER_QUAD;
+ break;
+
+ case 6: // 5.1
+ channelMask = SL_ANDROID_SPEAKER_5DOT1;
+ break;
+
+ case 8: // 7.1
+ channelMask = SL_ANDROID_SPEAKER_7DOT1;
+ break;
+ }
+ return channelMask;
+}
diff --git a/tests/tests/media/libndkaudio/OpenSLESUtils.h b/tests/tests/media/libndkaudio/OpenSLESUtils.h
new file mode 100644
index 0000000..89dde3d
--- /dev/null
+++ b/tests/tests/media/libndkaudio/OpenSLESUtils.h
@@ -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.
+ */
+
+#ifndef _OPENSLESUTILS_H_
+#define _OPENSLESUTILS_H_
+
+const char * getSLErrStr(int code);
+int chanCountToChanMask(int chanCount);
+
+#endif // _OPENSLESUTILS_H_
diff --git a/tests/tests/media/libndkaudio/PeriodicAudioSource.cpp b/tests/tests/media/libndkaudio/PeriodicAudioSource.cpp
new file mode 100644
index 0000000..a861bb8
--- /dev/null
+++ b/tests/tests/media/libndkaudio/PeriodicAudioSource.cpp
@@ -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.
+ */
+
+#include "PeriodicAudioSource.h"
+
+namespace ndkaudio {
+
+PeriodicAudioSource::PeriodicAudioSource(int numChannels)
+ : AudioSource(numChannels), targetFreq_(1000.0f) {
+}
+
+} // namespace ndkaudio
diff --git a/tests/tests/media/libndkaudio/PeriodicAudioSource.h b/tests/tests/media/libndkaudio/PeriodicAudioSource.h
new file mode 100644
index 0000000..ebb4a02
--- /dev/null
+++ b/tests/tests/media/libndkaudio/PeriodicAudioSource.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef PERIODICAUDIOSOURCE_H_
+#define PERIODICAUDIOSOURCE_H_
+
+#include "AudioSource.h"
+
+namespace ndkaudio {
+
+class PeriodicAudioSource : public AudioSource {
+ public:
+ PeriodicAudioSource(int numChannels);
+
+ void setAudioFrequency(float freq) {
+ targetFreq_ = freq;
+ }
+
+ float calcCurrentFreq(long time);
+
+ protected:
+ float targetFreq_;
+};
+
+} // namespace ndkaudio
+
+#endif /* PERIODICAUDIOSOURCE_H_ */
diff --git a/tests/tests/media/libndkaudio/SystemParams.cpp b/tests/tests/media/libndkaudio/SystemParams.cpp
new file mode 100644
index 0000000..c7f58f4
--- /dev/null
+++ b/tests/tests/media/libndkaudio/SystemParams.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#include "SystemParams.h"
+
+namespace ndkaudio {
+
+int SystemParams::sysSampleRate_ = 48000;
+int SystemParams::sysBuffFrames_ = 480;
+
+void SystemParams::init(int sysSampleRate, int sysBuffFrames) {
+ sysSampleRate_ = sysSampleRate;
+ sysBuffFrames_ = sysBuffFrames;
+}
+
+} // namespace ndkaudio
diff --git a/tests/tests/media/libndkaudio/SystemParams.h b/tests/tests/media/libndkaudio/SystemParams.h
new file mode 100644
index 0000000..96e9af0
--- /dev/null
+++ b/tests/tests/media/libndkaudio/SystemParams.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEMPARAMS_H_
+#define SYSTEMPARAMS_H_
+
+namespace ndkaudio {
+
+class SystemParams {
+ public:
+ static void init(int sysSampleRate, int sysBuffFrames);
+
+ static int getSampleRate() {
+ return sysSampleRate_;
+ }
+ static int getNumBufferFrames() {
+ return sysBuffFrames_;
+ }
+
+ private:
+ static int sysSampleRate_;
+ static int sysBuffFrames_;
+};
+
+} // namespace ndkaudio
+
+#endif /* SYSTEMPARAMS_H_ */
diff --git a/tests/tests/media/libndkaudio/WaveTableGenerator.cpp b/tests/tests/media/libndkaudio/WaveTableGenerator.cpp
new file mode 100644
index 0000000..5df87e7
--- /dev/null
+++ b/tests/tests/media/libndkaudio/WaveTableGenerator.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include <math.h>
+
+#include <android/log.h>
+
+#include "WaveTableGenerator.h"
+
+static const float kPI = 3.14159265359; // close enough
+
+//static const char* const TAG = "WaveTableGenerator";
+
+namespace ndkaudio {
+
+float* WaveTableGenerator::genSinWave(int size, float maxValue) {
+ return genSinWave(size, maxValue, new float[size]);
+}
+
+float* WaveTableGenerator::genSinWave(int size, float maxValue, float* tbl) {
+ float incr = (kPI * 2.0f) / (float) size;
+ float val = 0.0f;
+ for (int index = 0; index < size; index++) {
+ tbl[index] = (float) sin(val) * maxValue;
+ val += incr;
+ }
+
+ return tbl;
+}
+
+} // namespace ndkaudio
diff --git a/tests/tests/media/libndkaudio/WaveTableGenerator.h b/tests/tests/media/libndkaudio/WaveTableGenerator.h
new file mode 100644
index 0000000..fbe188a
--- /dev/null
+++ b/tests/tests/media/libndkaudio/WaveTableGenerator.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef WAVETABLEGENERATOR_H_
+#define WAVETABLEGENERATOR_H_
+
+namespace ndkaudio {
+
+class WaveTableGenerator {
+ public:
+ // SINE
+ static float* genSinWave(int size, float maxValue);
+ static float* genSinWave(int size, float maxValue, float* tbl);
+};
+
+} // namespace ndkaudio
+
+#endif /* WAVETABLEGENERATOR_H_ */
diff --git a/tests/tests/media/libndkaudio/WaveTableOscillator.cpp b/tests/tests/media/libndkaudio/WaveTableOscillator.cpp
new file mode 100644
index 0000000..2b7f850
--- /dev/null
+++ b/tests/tests/media/libndkaudio/WaveTableOscillator.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#include <android/log.h>
+
+//static const char * const TAG = "WaveTableOscillator";
+
+#include "WaveTableOscillator.h"
+#include "SystemParams.h"
+
+namespace ndkaudio {
+
+WaveTableOscillator::WaveTableOscillator(int numChannels, float* waveTable,
+ int waveTableSize)
+ : PeriodicAudioSource(numChannels),
+ waveTable_(waveTable),
+ waveTableSize_(waveTableSize),
+ fN_(0.0f),
+ srcPhase_(0.0f),
+ prevFillTime_(0)
+{
+ setWaveTable(waveTable, waveTableSize);
+}
+
+void WaveTableOscillator::setWaveTable(float* waveTable, int waveTableSize) {
+ waveTable_ = waveTable;
+ waveTableSize_ = waveTableSize - 1;
+
+ // The frequency that would be played if we took every sample from the table and
+ // played it at the system sample-rate. The "Nominal" frequency
+ fN_ = SystemParams::getSampleRate() / (float) waveTableSize_;
+}
+
+int WaveTableOscillator::getData(long time, float* outBuff, int numFrames,
+ int /*outChans*/) {
+ prevFillTime_ = time;
+
+ // Frequency - main
+ float currentFreq = targetFreq_;
+
+ float phaseIncr = currentFreq / fN_;
+
+// __android_log_print(ANDROID_LOG_INFO, TAG, "getData() freq:%f, fN_:%f, phs:%f incr:%f", currentFreq, fN_, srcPhase_, phaseIncr);
+
+ if (numChannels_ == 1) {
+ // calculate wave values
+ for (int dstIndex = 0; dstIndex < numFrames; ++dstIndex) {
+ // 'mod' back into the waveTable
+ if (srcPhase_ >= (float) waveTableSize_) {
+ srcPhase_ -= (float) waveTableSize_;
+ }
+
+ // linear-interpolate
+ int srcIndex = (int) srcPhase_;
+ float delta0 = srcPhase_ - srcIndex;
+ float delta1 = 1.0f - delta0;
+ outBuff[dstIndex] = ((waveTable_[srcIndex] * delta1)
+ + (waveTable_[srcIndex + 1] * delta0)) / 2.0f;
+
+ srcPhase_ += phaseIncr;
+ }
+ } else if (numChannels_ == 2) {
+ // calculate wave values
+ int dstIndex = 0;
+ for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
+ // 'mod' back into the waveTable
+ if (srcPhase_ >= (float) waveTableSize_) {
+ srcPhase_ -= (float) waveTableSize_;
+ }
+
+ // linear-interpolate
+ int srcIndex = (int) srcPhase_;
+ float delta0 = srcPhase_ - srcIndex;
+ float delta1 = 1.0f - delta0;
+ float out = ((waveTable_[srcIndex] * delta1)
+ + (waveTable_[srcIndex + 1] * delta0)) / 2.0f;
+
+ outBuff[dstIndex++] = out;
+ outBuff[dstIndex++] = out;
+
+ srcPhase_ += phaseIncr;
+ }
+ }
+
+// __android_log_print(ANDROID_LOG_INFO, TAG, " %d samples", numSamples);
+ return numFrames;
+}
+
+} // namespace ndkaudio
diff --git a/tests/tests/media/libndkaudio/WaveTableOscillator.h b/tests/tests/media/libndkaudio/WaveTableOscillator.h
new file mode 100644
index 0000000..aaccaf3
--- /dev/null
+++ b/tests/tests/media/libndkaudio/WaveTableOscillator.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef WAVETABLEOSCILLATOR_H_
+#define WAVETABLEOSCILLATOR_H_
+
+#include "PeriodicAudioSource.h"
+
+namespace ndkaudio {
+
+/*
+ * The assumption here is that the provided wave table contains 1 cycle of the wave
+ * and that the first and last samples are the same.
+ */
+class WaveTableOscillator : public PeriodicAudioSource {
+ public:
+ WaveTableOscillator(int numChannels, float* waveTable, int waveTableSize);
+
+ void setWaveTable(float* waveTable, int waveTableSize);
+
+ int getData(long time, float* outBuff, int numFrames, int outChans);
+
+ private:
+ float* waveTable_;
+ int waveTableSize_;
+
+ // 'nominal' frequency (i.e. how many times we step through the
+ // 1-cycle wave table in a second
+ float fN_;
+
+ // current pointer into the wave table
+ float srcPhase_;
+
+ // profiling
+ long prevFillTime_;
+};
+
+} // namespace ndkaudio
+
+#endif /* WAVETABLEOSCILLATOR_H_ */
diff --git a/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioPlayer.cpp b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioPlayer.cpp
new file mode 100644
index 0000000..a5b480e
--- /dev/null
+++ b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioPlayer.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+#include <android/log.h>
+
+#include "com_android_ndkaudio_AudioPlayer.h"
+
+#include "AudioPlayer.h"
+#include "WaveTableGenerator.h"
+#include "WaveTableOscillator.h"
+#include "SystemParams.h"
+
+static const char* TAG = "_com_android_ndkaudio_AudioPlayer_";
+
+using namespace ndkaudio;
+
+static int numChannels = 2;
+static int waveTableSize = 0;
+static float * waveTable = 0;
+
+static WaveTableOscillator* waveTableSource;
+static AudioPlayer* nativePlayer;
+
+static SLresult lastSLResult = 0;
+
+extern "C" {
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Create(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_Create() ...");
+
+ if (nativePlayer == 0) {
+ waveTableSize = SystemParams::getNumBufferFrames();
+ waveTable = WaveTableGenerator::genSinWave(waveTableSize, 1.0f);
+ waveTableSource = new WaveTableOscillator(numChannels, waveTable, waveTableSize);
+
+ nativePlayer = new AudioPlayer();
+ nativePlayer->Open(numChannels, waveTableSource);
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Destroy(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_Destroy() ...");
+ nativePlayer->Close();
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_RealizePlayer(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_RealizePlayer() ...");
+ nativePlayer->RealizePlayer();
+ }
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_RealizeRoutingProxy(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_RealizeRoutingProxy() ...");
+ nativePlayer->RealizeRoutingProxy();
+ }
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Start(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_Start() ...");
+ nativePlayer->Start();
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Stop(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_Stop() ...");
+ nativePlayer->Stop();
+}
+
+JNIEXPORT jobject JNICALL Java_com_android_ndkaudio_AudioPlayer_GetRoutingInterface(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_GetRoutingInterface() ...");
+
+ SLAndroidConfigurationItf configItf = nativePlayer->getConfigItf();
+ __android_log_print(ANDROID_LOG_INFO, TAG, " configItf:%p", configItf);
+ jobject routingObj = 0;
+ lastSLResult = (*configItf)->AcquireJavaProxy(configItf, SL_ANDROID_JAVA_PROXY_ROUTING, &routingObj);
+ __android_log_print(ANDROID_LOG_INFO, TAG, " routingObj:%p", routingObj);
+ return routingObj;
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_ReleaseRoutingInterface(JNIEnv*, jobject, jobject /*proxyObj*/) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_ReleaseRoutingInterface() ...");
+
+ SLAndroidConfigurationItf configItf = nativePlayer->getConfigItf();
+ lastSLResult = (*configItf)->ReleaseJavaProxy(configItf, SL_ANDROID_JAVA_PROXY_ROUTING/*, proxyObj*/);
+}
+
+JNIEXPORT long JNICALL Java_com_android_ndkaudio_AudioPlayer_GetLastSLResult(JNIEnv*, jobject) {
+ return lastSLResult;
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_ClearLastSLResult(JNIEnv*, jobject) {
+ lastSLResult = 0;
+}
+
+} // extern "C"
diff --git a/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioPlayer.h b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioPlayer.h
new file mode 100644
index 0000000..e01d3ac
--- /dev/null
+++ b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioPlayer.h
@@ -0,0 +1,99 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_ndkaudio_AudioPlayer */
+
+#ifndef _Included_com_android_ndkaudio_AudioPlayer
+#define _Included_com_android_ndkaudio_AudioPlayer
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: InitN
+ * Signature: ()V
+ */
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: Create
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Create
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: Destroy
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Destroy
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: RealizePlayer
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_RealizePlayer
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: RealizeRoutingProxy
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_RealizeRoutingProxy
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: Start
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Start
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: Stop
+ * Signature: ()android/
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_Stop
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: GetRoutingInterface
+ * Signature: ()Landroid/media/AudioRouting;
+ */
+JNIEXPORT jobject JNICALL Java_com_android_ndkaudio_AudioPlayer_GetRoutingInterface
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: GetRoutingInterface
+ * Signature: (Landroid/media/AudioRouting;)V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_ReleaseRoutingInterface
+ (JNIEnv*, jobject, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: GetLastSLResult
+ * Signature: ()J
+ */
+JNIEXPORT long JNICALL Java_com_android_ndkaudio_AudioPlayer_GetLastSLResult
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioPlayer
+ * Method: ClearLastSLResult
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioPlayer_ClearLastSLResult
+ (JNIEnv*, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioRecorder.cpp b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioRecorder.cpp
new file mode 100644
index 0000000..e7b6abd
--- /dev/null
+++ b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioRecorder.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+#include <android/log.h>
+
+#include "com_android_ndkaudio_AudioRecorder.h"
+
+#include "AudioRecorder.h"
+
+using namespace ndkaudio;
+
+static const char* TAG = "_com_android_ndkaudio_AudioRecorder_";
+
+static int numChannels = 2;
+
+static AudioRecorder* nativeRecorder;
+
+static SLresult lastSLResult = 0;
+extern "C" {
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Create(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioRecorder_Create() ...");
+ if (nativeRecorder == 0) {
+ nativeRecorder = new AudioRecorder();
+ }
+ nativeRecorder->Open(numChannels, 0);
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Destroy(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioRecorder_Destroy() ...");
+ nativeRecorder->Close();
+ delete nativeRecorder;
+ nativeRecorder = 0;
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_RealizeRecorder(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioRecorder_RealizePlayer() ...");
+ nativeRecorder->RealizeRecorder();
+ }
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_RealizeRoutingProxy(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "RealizeRoutingProxy ...");
+ nativeRecorder->RealizeRoutingProxy();
+ }
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Start(JNIEnv *, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioRecorder_Start() ...");
+ nativeRecorder->Start();
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Stop(JNIEnv *, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioRecorder_Stop() ...");
+ nativeRecorder->Stop();
+}
+
+JNIEXPORT jobject JNICALL Java_com_android_ndkaudio_AudioRecorder_GetRoutingInterface(JNIEnv*, jobject) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_GetRoutingObj() ...");
+
+ SLAndroidConfigurationItf configItf = nativeRecorder->getConfigItf();
+ jobject routingObj = 0;
+ lastSLResult = (*configItf)->AcquireJavaProxy(configItf, SL_ANDROID_JAVA_PROXY_ROUTING, &routingObj);
+ __android_log_print(ANDROID_LOG_INFO, TAG, " routingObj:%p", routingObj);
+ return routingObj;
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_ReleaseRoutingInterface(JNIEnv*, jobject, jobject /*proxyObj*/) {
+ __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayer_GetRoutingObj() ...");
+
+ SLAndroidConfigurationItf configItf = nativeRecorder->getConfigItf();
+ lastSLResult = (*configItf)->ReleaseJavaProxy(configItf, SL_ANDROID_JAVA_PROXY_ROUTING/*, proxyObj*/);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_ndkaudio_AudioRecorder_GetNumBufferSamples(JNIEnv*, jobject) {
+ return nativeRecorder->GetNumBufferSamples();
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_GetBufferData(JNIEnv* jEnv, jobject, jfloatArray j_data) {
+ float* dataBuffer = nativeRecorder->GetRecordBuffer();
+ if (dataBuffer != 0) {
+ jEnv->SetFloatArrayRegion(j_data, 0, nativeRecorder->GetNumBufferSamples(), dataBuffer);
+ }
+}
+
+JNIEXPORT long JNICALL Java_com_android_ndkaudio_AudioRecorder_GetLastSLResult(JNIEnv*, jobject) {
+ return lastSLResult;
+}
+
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_ClearLastSLResult(JNIEnv*, jobject) {
+ lastSLResult = 0;
+}
+
+} // extern "C"
diff --git a/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioRecorder.h b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioRecorder.h
new file mode 100644
index 0000000..d35d4b0
--- /dev/null
+++ b/tests/tests/media/libndkaudio/com_android_ndkaudio_AudioRecorder.h
@@ -0,0 +1,109 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_ndkaudio_AudioRecorder */
+
+#ifndef _Included_com_android_ndkaudio_AudioRecorder
+#define _Included_com_android_ndkaudio_AudioRecorder
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: Create
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Create
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: Destroy
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Destroy
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: RealizeRecorder
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_RealizeRecorder
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: RealizeRoutingProxy
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_RealizeRoutingProxy
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: Start
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Start
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: Stop
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_Stop
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: GetRoutingInterface
+ * Signature: ()Landroid/media/AudioRouting;
+ */
+JNIEXPORT jobject JNICALL Java_com_android_ndkaudio_AudioRecorder_GetRoutingInterface
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: ReleaseRoutingInterface
+ * Signature: (Landroid/media/AudioRouting;)V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_ReleaseRoutingInterface
+ (JNIEnv*, jobject, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: GetNumBufferFrames
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_android_ndkaudio_AudioRecorder_GetNumBufferFrames
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: GetBufferData
+ * Signature: ([F)V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_GetBufferData
+ (JNIEnv *, jobject, jfloatArray);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: GetLastSLResult
+ * Signature: ()J
+ */
+JNIEXPORT long JNICALL Java_com_android_ndkaudio_AudioRecorder_GetLastSLResult
+ (JNIEnv*, jobject);
+
+/*
+ * Class: com_android_ndkaudio_AudioRecorder
+ * Method: ClearLastSLResult
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_ndkaudio_AudioRecorder_ClearLastSLResult
+ (JNIEnv*, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tests/tests/media/libndkaudio/src/com/android/ndkaudio/AudioPlayer.java b/tests/tests/media/libndkaudio/src/com/android/ndkaudio/AudioPlayer.java
new file mode 100644
index 0000000..f9cd109
--- /dev/null
+++ b/tests/tests/media/libndkaudio/src/com/android/ndkaudio/AudioPlayer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ndkaudio;
+
+import android.media.AudioRouting;
+
+public class AudioPlayer {
+ public AudioPlayer() {
+ Create();
+ }
+
+ public native void Create();
+ public native void Destroy();
+
+ public native void RealizePlayer();
+ public native void RealizeRoutingProxy();
+
+ public native void Start();
+ public native void Stop();
+
+ public native AudioRouting GetRoutingInterface();
+
+ public native void ReleaseRoutingInterface(AudioRouting proxyObj);
+
+ public native long GetLastSLResult();
+ public native void ClearLastSLResult();
+}
diff --git a/tests/tests/media/libndkaudio/src/com/android/ndkaudio/AudioRecorder.java b/tests/tests/media/libndkaudio/src/com/android/ndkaudio/AudioRecorder.java
new file mode 100644
index 0000000..52d20c4
--- /dev/null
+++ b/tests/tests/media/libndkaudio/src/com/android/ndkaudio/AudioRecorder.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ndkaudio;
+
+import android.media.AudioRouting;
+
+public class AudioRecorder {
+ public AudioRecorder() {
+ Create();
+ }
+
+ public native void Create();
+ public native void Destroy();
+
+ public native void RealizeRecorder();
+ public native void RealizeRoutingProxy();
+
+ public native void Start();
+ public native void Stop();
+
+ public native AudioRouting GetRoutingInterface();
+ public native void ReleaseRoutingInterface(AudioRouting proxyObj);
+
+ public native int GetNumBufferSamples();
+ public native void GetBufferData(float[] dstBuff);
+
+ public native long GetLastSLResult();
+ public native void ClearLastSLResult();
+}
diff --git a/tests/tests/media/res/raw/sine1khzm40db.wav b/tests/tests/media/res/raw/sine1khzm40db.wav
index ba541c4..b653a77 100644
--- a/tests/tests/media/res/raw/sine1khzm40db.wav
+++ b/tests/tests/media/res/raw/sine1khzm40db.wav
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 16b1cf3..c78f82a 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -35,8 +35,6 @@
import static android.media.AudioManager.VIBRATE_TYPE_RINGER;
import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED;
-import android.media.cts.R;
-
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
@@ -48,8 +46,6 @@
import android.test.InstrumentationTestCase;
import android.view.SoundEffectConstants;
-import java.util.TreeMap;
-
public class AudioManagerTest extends InstrumentationTestCase {
private final static int MP3_TO_PLAY = R.raw.testmp3;
@@ -184,294 +180,417 @@
if (mUseFixedVolume || !mHasVibrator) {
return;
}
- // VIBRATE_SETTING_ON
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ // VIBRATE_SETTING_ON
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
- assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- // VIBRATE_SETTING_OFF
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF);
- assertEquals(VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ // VIBRATE_SETTING_OFF
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF);
+ assertEquals(VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- // VIBRATE_SETTING_ONLY_SILENT
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ // VIBRATE_SETTING_ONLY_SILENT
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
- assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
- // VIBRATE_TYPE_NOTIFICATION
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF);
- assertEquals(VIBRATE_SETTING_OFF, mAudioManager
- .getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ // VIBRATE_TYPE_NOTIFICATION
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF);
+ assertEquals(VIBRATE_SETTING_OFF, mAudioManager
+ .getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
}
public void testVibrateRinger() throws Exception {
if (mUseFixedVolume || !mHasVibrator) {
return;
}
- // VIBRATE_TYPE_RINGER
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ // VIBRATE_TYPE_RINGER
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
- assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- // VIBRATE_SETTING_OFF
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF);
- assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ // VIBRATE_SETTING_OFF
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF);
+ assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
- // Note: as of Froyo, if VIBRATE_TYPE_RINGER is set to OFF, it will
- // not vibrate, even in RINGER_MODE_VIBRATE. This allows users to
- // disable the vibration for incoming calls only.
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ // Note: as of Froyo, if VIBRATE_TYPE_RINGER is set to OFF, it will
+ // not vibrate, even in RINGER_MODE_VIBRATE. This allows users to
+ // disable the vibration for incoming calls only.
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- // VIBRATE_SETTING_ONLY_SILENT
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ // VIBRATE_SETTING_ONLY_SILENT
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
- assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
- // VIBRATE_TYPE_NOTIFICATION
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF);
- assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
- mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT);
- assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
- mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ // VIBRATE_TYPE_NOTIFICATION
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF);
+ assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT);
+ assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
+ mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
}
public void testAccessRingMode() throws Exception {
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
-
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- // AudioService#setRingerMode() has:
- // if (isTelevision) return;
- if (mUseFixedVolume || mIsTelevision) {
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
- } else {
+
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ // AudioService#setRingerMode() has:
+ // if (isTelevision) return;
+ if (mUseFixedVolume || mIsTelevision) {
+ assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ } else {
+ assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+ }
+
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ if (mUseFixedVolume || mIsTelevision) {
+ assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ } else {
+ assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
+ mAudioManager.getRingerMode());
+ }
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
+ }
+
+ public void testSetRingerModePolicyAccess() throws Exception {
+ try {
+ // Apps without policy access cannot change silent -> normal or silent -> vibrate.
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode());
- }
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- if (mUseFixedVolume || mIsTelevision) {
+ try {
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {
+ }
+
+ try {
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {
+ }
+
+ // Apps without policy access cannot change normal -> silent.
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
- } else {
- assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
- mAudioManager.getRingerMode());
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+
+ try {
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {
+ }
+ assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+
+ // Apps without policy access cannot change vibrate -> silent.
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+
+ try {
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {
+ }
+
+ // Apps without policy access can change vibrate -> normal and vice versa.
+ assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
}
}
+ public void testVolumeDndAffectedStream() throws Exception {
+ if (mUseFixedVolume || mHasVibrator) {
+ return;
+ }
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_SYSTEM, 7, AudioManager.FLAG_ALLOW_RINGER_MODES);
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ // 7 to 0, fail.
+ try {
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_SYSTEM, 0, AudioManager.FLAG_ALLOW_RINGER_MODES);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {}
+
+ // 7 to 1: success
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_SYSTEM, 1, AudioManager.FLAG_ALLOW_RINGER_MODES);
+ assertEquals("setStreamVolume did not change volume",
+ 1, mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM));
+
+ // 0 to non-zero: fail.
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_SYSTEM, 0, AudioManager.FLAG_ALLOW_RINGER_MODES);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+
+ try {
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_SYSTEM, 6, AudioManager.FLAG_ALLOW_RINGER_MODES);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {}
+ }
+
public void testVolume() throws Exception {
- int volume, volumeDelta;
- int[] streams = { AudioManager.STREAM_ALARM,
- AudioManager.STREAM_MUSIC,
- AudioManager.STREAM_VOICE_CALL,
- AudioManager.STREAM_RING };
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ int volume, volumeDelta;
+ int[] streams = {AudioManager.STREAM_ALARM,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.STREAM_VOICE_CALL,
+ AudioManager.STREAM_RING};
- mAudioManager.adjustVolume(ADJUST_RAISE, 0);
- mAudioManager.adjustSuggestedStreamVolume(
- ADJUST_LOWER, USE_DEFAULT_STREAM_TYPE, 0);
- int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
+ mAudioManager.adjustVolume(ADJUST_RAISE, 0);
+ mAudioManager.adjustSuggestedStreamVolume(
+ ADJUST_LOWER, USE_DEFAULT_STREAM_TYPE, 0);
+ int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
- for (int i = 0; i < streams.length; i++) {
- // set ringer mode to back normal to not interfere with volume tests
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ for (int i = 0; i < streams.length; i++) {
+ // set ringer mode to back normal to not interfere with volume tests
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- int maxVolume = mAudioManager.getStreamMaxVolume(streams[i]);
- int minVolume = mAudioManager.getStreamMinVolume(streams[i]);
+ int maxVolume = mAudioManager.getStreamMaxVolume(streams[i]);
+ int minVolume = mAudioManager.getStreamMinVolume(streams[i]);
- // validate min
- assertTrue(String.format("minVolume(%d) must be >= 0", minVolume), minVolume >= 0);
- assertTrue(String.format("minVolume(%d) must be < maxVolume(%d)", minVolume, maxVolume),
- minVolume < maxVolume);
+ // validate min
+ assertTrue(String.format("minVolume(%d) must be >= 0", minVolume), minVolume >= 0);
+ assertTrue(String.format("minVolume(%d) must be < maxVolume(%d)", minVolume,
+ maxVolume),
+ minVolume < maxVolume);
- mAudioManager.setStreamVolume(streams[i], 1, 0);
- if (mUseFixedVolume) {
- assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
- continue;
- }
- assertEquals(1, mAudioManager.getStreamVolume(streams[i]));
+ mAudioManager.setStreamVolume(streams[i], 1, 0);
+ if (mUseFixedVolume) {
+ assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
+ continue;
+ }
+ assertEquals(1, mAudioManager.getStreamVolume(streams[i]));
- if (streams[i] == AudioManager.STREAM_MUSIC && mAudioManager.isWiredHeadsetOn()) {
- // due to new regulations, music sent over a wired headset may be volume limited
- // until the user explicitly increases the limit, so we can't rely on being able
- // to set the volume to getStreamMaxVolume(). Instead, determine the current limit
- // by increasing the volume until it won't go any higher, then use that volume as
- // the maximum for the purposes of this test
- int curvol = 0;
- int prevvol = 0;
- do {
- prevvol = curvol;
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
- curvol = mAudioManager.getStreamVolume(streams[i]);
- } while (curvol != prevvol);
- maxVolume = maxMusicVolume = curvol;
- }
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
- assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
-
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
- mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, streams[i], 0);
- assertEquals(maxVolume - volumeDelta, mAudioManager.getStreamVolume(streams[i]));
-
- // volume lower
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
- volume = mAudioManager.getStreamVolume(streams[i]);
- while (volume > minVolume) {
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_LOWER, 0);
- assertEquals(Math.max(0, volume - volumeDelta),
- mAudioManager.getStreamVolume(streams[i]));
- volume = mAudioManager.getStreamVolume(streams[i]);
- }
-
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
-
- // volume raise
- mAudioManager.setStreamVolume(streams[i], 1, 0);
- volume = mAudioManager.getStreamVolume(streams[i]);
- while (volume < maxVolume) {
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
+ if (streams[i] == AudioManager.STREAM_MUSIC && mAudioManager.isWiredHeadsetOn()) {
+ // due to new regulations, music sent over a wired headset may be volume limited
+ // until the user explicitly increases the limit, so we can't rely on being able
+ // to set the volume to getStreamMaxVolume(). Instead, determine the current limit
+ // by increasing the volume until it won't go any higher, then use that volume as
+ // the maximum for the purposes of this test
+ int curvol = 0;
+ int prevvol = 0;
+ do {
+ prevvol = curvol;
+ mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
+ curvol = mAudioManager.getStreamVolume(streams[i]);
+ } while (curvol != prevvol);
+ maxVolume = maxMusicVolume = curvol;
+ }
+ mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
- assertEquals(Math.min(volume + volumeDelta, maxVolume),
- mAudioManager.getStreamVolume(streams[i]));
- volume = mAudioManager.getStreamVolume(streams[i]);
- }
-
- // volume same
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
- for (int k = 0; k < maxVolume; k++) {
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
+
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
+ mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, streams[i], 0);
+ assertEquals(maxVolume - volumeDelta, mAudioManager.getStreamVolume(streams[i]));
+
+ // volume lower
+ mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
+ volume = mAudioManager.getStreamVolume(streams[i]);
+ while (volume > minVolume) {
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
+ mAudioManager.adjustStreamVolume(streams[i], ADJUST_LOWER, 0);
+ assertEquals(Math.max(0, volume - volumeDelta),
+ mAudioManager.getStreamVolume(streams[i]));
+ volume = mAudioManager.getStreamVolume(streams[i]);
+ }
+
+ mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
+
+ // volume raise
+ mAudioManager.setStreamVolume(streams[i], 1, 0);
+ volume = mAudioManager.getStreamVolume(streams[i]);
+ while (volume < maxVolume) {
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
+ mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
+ assertEquals(Math.min(volume + volumeDelta, maxVolume),
+ mAudioManager.getStreamVolume(streams[i]));
+ volume = mAudioManager.getStreamVolume(streams[i]);
+ }
+
+ // volume same
+ mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
+ for (int k = 0; k < maxVolume; k++) {
+ mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
+ assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
+ }
+
+ mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
}
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
+ if (mUseFixedVolume) {
+ return;
+ }
+
+ // adjust volume
+ mAudioManager.adjustVolume(ADJUST_RAISE, 0);
+
+ MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY);
+ assertNotNull(mp);
+ mp.setAudioStreamType(STREAM_MUSIC);
+ mp.setLooping(true);
+ mp.start();
+ Thread.sleep(TIME_TO_PLAY);
+ assertTrue(mAudioManager.isMusicActive());
+
+ // adjust volume as ADJUST_SAME
+ for (int k = 0; k < maxMusicVolume; k++) {
+ mAudioManager.adjustVolume(ADJUST_SAME, 0);
+ assertEquals(maxMusicVolume, mAudioManager.getStreamVolume(STREAM_MUSIC));
+ }
+
+ // adjust volume as ADJUST_RAISE
+ mAudioManager.setStreamVolume(STREAM_MUSIC, 0, 0);
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
+ mAudioManager.adjustVolume(ADJUST_RAISE, 0);
+ assertEquals(Math.min(volumeDelta, maxMusicVolume),
+ mAudioManager.getStreamVolume(STREAM_MUSIC));
+
+ // adjust volume as ADJUST_LOWER
+ mAudioManager.setStreamVolume(STREAM_MUSIC, maxMusicVolume, 0);
+ maxMusicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
+ mAudioManager.adjustVolume(ADJUST_LOWER, 0);
+ assertEquals(Math.max(0, maxMusicVolume - volumeDelta),
+ mAudioManager.getStreamVolume(STREAM_MUSIC));
+
+ mp.stop();
+ mp.release();
+ Thread.sleep(TIME_TO_PLAY);
+ assertFalse(mAudioManager.isMusicActive());
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
}
-
- if (mUseFixedVolume) {
- return;
- }
-
- // adjust volume
- mAudioManager.adjustVolume(ADJUST_RAISE, 0);
-
- MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY);
- assertNotNull(mp);
- mp.setAudioStreamType(STREAM_MUSIC);
- mp.setLooping(true);
- mp.start();
- Thread.sleep(TIME_TO_PLAY);
- assertTrue(mAudioManager.isMusicActive());
-
- // adjust volume as ADJUST_SAME
- for (int k = 0; k < maxMusicVolume; k++) {
- mAudioManager.adjustVolume(ADJUST_SAME, 0);
- assertEquals(maxMusicVolume, mAudioManager.getStreamVolume(STREAM_MUSIC));
- }
-
- // adjust volume as ADJUST_RAISE
- mAudioManager.setStreamVolume(STREAM_MUSIC, 0, 0);
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
- mAudioManager.adjustVolume(ADJUST_RAISE, 0);
- assertEquals(Math.min(volumeDelta, maxMusicVolume),
- mAudioManager.getStreamVolume(STREAM_MUSIC));
-
- // adjust volume as ADJUST_LOWER
- mAudioManager.setStreamVolume(STREAM_MUSIC, maxMusicVolume, 0);
- maxMusicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
- mAudioManager.adjustVolume(ADJUST_LOWER, 0);
- assertEquals(Math.max(0, maxMusicVolume - volumeDelta),
- mAudioManager.getStreamVolume(STREAM_MUSIC));
-
- mp.stop();
- mp.release();
- Thread.sleep(TIME_TO_PLAY);
- assertFalse(mAudioManager.isMusicActive());
}
- public void testMute() {
+ public void testMuteFixedVolume() throws Exception {
int[] streams = {
AudioManager.STREAM_VOICE_CALL,
AudioManager.STREAM_MUSIC,
AudioManager.STREAM_RING,
AudioManager.STREAM_ALARM,
AudioManager.STREAM_NOTIFICATION,
- AudioManager.STREAM_SYSTEM };
-
- int muteAffectedStreams = System.getInt(mContext.getContentResolver(),
- System.MUTE_STREAMS_AFFECTED,
- // Same defaults as in AudioService. Should be kept in
- // sync.
- ((1 << AudioManager.STREAM_MUSIC) |
- (1 << AudioManager.STREAM_RING) |
- (1 << AudioManager.STREAM_NOTIFICATION) |
- (1 << AudioManager.STREAM_SYSTEM)));
+ AudioManager.STREAM_SYSTEM};
if (mUseFixedVolume) {
for (int i = 0; i < streams.length; i++) {
mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
@@ -486,54 +605,87 @@
assertFalse("Muting should not affect a fixed volume device.",
mAudioManager.isStreamMute(streams[i]));
}
+ }
+ }
+
+ public void testMute() throws Exception {
+ if (mUseFixedVolume) {
return;
}
- // This ensures we're out of vibrate or silent modes.
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- for (int i = 0; i < streams.length; i++) {
- // ensure each stream is on and turned up.
- mAudioManager.setStreamVolume(streams[i], mAudioManager.getStreamMaxVolume(streams[i]),
- 0);
- if (((1 << streams[i]) & muteAffectedStreams) == 0) {
+
+ int[] streams = {
+ AudioManager.STREAM_VOICE_CALL,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.STREAM_RING,
+ AudioManager.STREAM_ALARM,
+ AudioManager.STREAM_NOTIFICATION,
+ AudioManager.STREAM_SYSTEM };
+
+ try {
+ int muteAffectedStreams = System.getInt(mContext.getContentResolver(),
+ System.MUTE_STREAMS_AFFECTED,
+ // Same defaults as in AudioService. Should be kept in
+ // sync.
+ ((1 << AudioManager.STREAM_MUSIC) |
+ (1 << AudioManager.STREAM_RING) |
+ (1 << AudioManager.STREAM_NOTIFICATION) |
+ (1 << AudioManager.STREAM_SYSTEM)));
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ // This ensures we're out of vibrate or silent modes.
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ for (int i = 0; i < streams.length; i++) {
+ // ensure each stream is on and turned up.
+ mAudioManager.setStreamVolume(streams[i],
+ mAudioManager.getStreamMaxVolume(streams[i]),
+ 0);
+ if (((1 << streams[i]) & muteAffectedStreams) == 0) {
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+ assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+ mAudioManager.isStreamMute(streams[i]));
+ mAudioManager.setStreamMute(streams[i], true);
+ assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+ mAudioManager.isStreamMute(streams[i]));
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE,
+ 0);
+ assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+ mAudioManager.isStreamMute(streams[i]));
+ continue;
+ }
mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
- assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+ assertTrue("Muting stream " + streams[i] + " failed.",
mAudioManager.isStreamMute(streams[i]));
- mAudioManager.setStreamMute(streams[i], true);
- assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
+ assertFalse("Unmuting stream " + streams[i] + " failed.",
mAudioManager.isStreamMute(streams[i]));
+
mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
- assertFalse("Stream " + streams[i] + " should not be affected by mute.",
+ assertTrue("Toggling mute on stream " + streams[i] + " failed.",
mAudioManager.isStreamMute(streams[i]));
- continue;
+
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+ assertFalse("Toggling mute on stream " + streams[i] + " failed.",
+ mAudioManager.isStreamMute(streams[i]));
+
+ mAudioManager.setStreamMute(streams[i], true);
+ assertTrue("Muting stream " + streams[i] + " using setStreamMute failed",
+ mAudioManager.isStreamMute(streams[i]));
+
+ // mute it three more times to verify the ref counting is gone.
+ mAudioManager.setStreamMute(streams[i], true);
+ mAudioManager.setStreamMute(streams[i], true);
+ mAudioManager.setStreamMute(streams[i], true);
+
+ mAudioManager.setStreamMute(streams[i], false);
+ assertFalse("Unmuting stream " + streams[i] + " using setStreamMute failed.",
+ mAudioManager.isStreamMute(streams[i]));
}
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
- assertTrue("Muting stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
- assertFalse("Unmuting stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
- assertTrue("Toggling mute on stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
- assertFalse("Toggling mute on stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.setStreamMute(streams[i], true);
- assertTrue("Muting stream " + streams[i] + " using setStreamMute failed",
- mAudioManager.isStreamMute(streams[i]));
-
- // mute it three more times to verify the ref counting is gone.
- mAudioManager.setStreamMute(streams[i], true);
- mAudioManager.setStreamMute(streams[i], true);
- mAudioManager.setStreamMute(streams[i], true);
-
- mAudioManager.setStreamMute(streams[i], false);
- assertFalse("Unmuting stream " + streams[i] + " using setStreamMute failed.",
- mAudioManager.isStreamMute(streams[i]));
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
}
}
@@ -549,4 +701,5 @@
private int getVolumeDelta(int volume) {
return 1;
}
+
}
diff --git a/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java b/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java
new file mode 100644
index 0000000..6156095
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java
@@ -0,0 +1,118 @@
+/*
+ * 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.cts.util.CtsAndroidTestCase;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioRouting;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.ndkaudio.AudioPlayer;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class AudioPlayRoutingNative extends AndroidTestCase {
+ private static final String TAG = "AudioPlayRoutingNative";
+
+ private AudioManager mAudioManager;
+
+ static {
+ System.loadLibrary("ndkaudioLib");
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // get the AudioManager
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ assertNotNull(mAudioManager);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ //
+ // Tests
+ //
+
+ // Test a basic Aquire/Release cycle on the default player.
+ public void testAquireDefaultProxy() throws Exception {
+ AudioPlayer player = new AudioPlayer();
+ player.ClearLastSLResult();
+ player.RealizePlayer();
+ player.RealizeRoutingProxy();
+
+ AudioRouting routingObj = player.GetRoutingInterface();
+ assertNotNull(routingObj);
+
+ // Not allowed to acquire twice
+ routingObj = player.GetRoutingInterface();
+ assertNull(routingObj);
+ assertTrue(player.GetLastSLResult() != 0);
+
+ player.ReleaseRoutingInterface(routingObj);
+ assertTrue(player.GetLastSLResult() == 0);
+ }
+
+ // Test an Aquire before the OpenSL ES player is Realized.
+ public void testAquirePreRealizeDefaultProxy() throws Exception {
+ AudioPlayer player = new AudioPlayer();
+ player.ClearLastSLResult();
+ player.RealizeRoutingProxy();
+ assertTrue(player.GetLastSLResult() == 0);
+
+ AudioRouting routingObj = player.GetRoutingInterface();
+ assertTrue(player.GetLastSLResult() == 0);
+ assertNotNull(routingObj);
+
+ player.RealizePlayer();
+ assertTrue(player.GetLastSLResult() == 0);
+
+ player.ReleaseRoutingInterface(routingObj);
+ assertTrue(player.GetLastSLResult() == 0);
+ }
+
+ // Test actually setting the routing through the enumerated devices.
+ public void testRouting() {
+ AudioPlayer player = new AudioPlayer();
+ player.ClearLastSLResult();
+ player.RealizePlayer();
+ player.RealizeRoutingProxy();
+
+ AudioRouting routingObj = player.GetRoutingInterface();
+ assertNotNull(routingObj);
+
+ AudioDeviceInfo[] deviceList;
+ deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ assertTrue(deviceList != null);
+ for (AudioDeviceInfo devInfo : deviceList) {
+ assertTrue(routingObj.setPreferredDevice(devInfo));
+ }
+
+ player.ReleaseRoutingInterface(routingObj);
+ assertTrue(player.GetLastSLResult() == 0);
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordRoutingNative.java b/tests/tests/media/src/android/media/cts/AudioRecordRoutingNative.java
new file mode 100644
index 0000000..c965e14
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/AudioRecordRoutingNative.java
@@ -0,0 +1,118 @@
+/*
+ * 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioRouting;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.ndkaudio.AudioRecorder;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class AudioRecordRoutingNative extends AndroidTestCase {
+ private static final String TAG = "AudioRecordRoutingNative";
+
+ private AudioManager mAudioManager;
+
+ static {
+ System.loadLibrary("ndkaudioLib");
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // get the AudioManager
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ assertNotNull(mAudioManager);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ //
+ // Tests
+ //
+
+ // Test a basic Aquire/Release cycle on the default recorder.
+ public void testAquireDefaultProxy() throws Exception {
+ AudioRecorder recorder = new AudioRecorder();
+ recorder.ClearLastSLResult();
+ recorder.RealizeRecorder();
+ recorder.RealizeRoutingProxy();
+
+ AudioRouting routingObj = recorder.GetRoutingInterface();
+ assertNotNull(routingObj);
+
+ // Not allowed to acquire twice
+ routingObj = recorder.GetRoutingInterface();
+ assertNull(routingObj);
+ assertTrue(recorder.GetLastSLResult() != 0);
+
+ recorder.ReleaseRoutingInterface(routingObj);
+ assertTrue(recorder.GetLastSLResult() == 0);
+ }
+
+ // Test an Aquire before the OpenSL ES recorder is Realized.
+ public void testAquirePreRealizeDefaultProxy() throws Exception {
+ AudioRecorder recorder = new AudioRecorder();
+ recorder.ClearLastSLResult();
+ recorder.RealizeRecorder();
+ recorder.RealizeRoutingProxy();
+ assertTrue(recorder.GetLastSLResult() == 0);
+
+ AudioRouting routingObj = recorder.GetRoutingInterface();
+ assertTrue(recorder.GetLastSLResult() == 0);
+ assertNotNull(routingObj);
+
+ recorder.RealizeRecorder();
+ assertTrue(recorder.GetLastSLResult() == 0);
+
+ recorder.ReleaseRoutingInterface(routingObj);
+ assertTrue(recorder.GetLastSLResult() == 0);
+ }
+
+ // Test actually setting the routing through the enumerated devices.
+ public void testRouting() {
+ AudioRecorder recorder = new AudioRecorder();
+ recorder.ClearLastSLResult();
+ recorder.RealizeRecorder();
+ recorder.RealizeRoutingProxy();
+
+ AudioRouting routingObj = recorder.GetRoutingInterface();
+ assertNotNull(routingObj);
+
+ AudioDeviceInfo[] deviceList;
+ deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+ assertTrue(deviceList != null);
+ for (AudioDeviceInfo devInfo : deviceList) {
+ assertTrue(routingObj.setPreferredDevice(devInfo));
+ }
+
+ recorder.ReleaseRoutingInterface(routingObj);
+ assertTrue(recorder.GetLastSLResult() == 0);
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index c2c729b..afd6997 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -749,7 +749,7 @@
return;
}
// audit recording plays back recorded audio, so use longer test timing
- final int TEST_TIME_MS = auditRecording ? 10000 : 2000;
+ final int TEST_TIME_MS = auditRecording ? 60000 : 2000;
final int TEST_SOURCE = MediaRecorder.AudioSource.DEFAULT;
mIsHandleMessageCalled = false;
@@ -1252,7 +1252,8 @@
final double ratio = (double)timeDiff / timeByFrames;
// Usually the ratio is accurate to one part per thousand or better.
- // Log.d(TAG, "ratio " + ratio);
+ // Log.d(TAG, "ratio=" + ratio + ", timeDiff=" + timeDiff + ", frameDiff=" + frameDiff +
+ // ", timeByFrames=" + timeByFrames + ", sampleRate=" + sampleRate);
assertEquals(1.0 /* expected */, ratio, 0.01 /* delta */);
}
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java b/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
index 505c4dc..0851a0a 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
@@ -54,7 +54,8 @@
public class AudioTrackLatencyTest extends CtsAndroidTestCase {
private String TAG = "AudioTrackLatencyTest";
private final static long NANOS_PER_MILLISECOND = 1000000L;
- private final static long NANOS_PER_SECOND = NANOS_PER_MILLISECOND * 1000L;
+ private final static int MILLIS_PER_SECOND = 1000;
+ private final static long NANOS_PER_SECOND = NANOS_PER_MILLISECOND * MILLIS_PER_SECOND;
private void log(String testName, String message) {
Log.i(TAG, "[" + testName + "] " + message);
@@ -97,8 +98,9 @@
initialBufferSize, track.getBufferSizeInFrames());
int resultZero = track.setBufferSizeInFrames(0);
- assertTrue(TEST_NAME + ": zero size OK", resultZero > 0);
- assertTrue(TEST_NAME + ": zero size < original", resultZero < initialBufferSize);
+ assertTrue(TEST_NAME + ": should be >0, but got " + resultZero, resultZero > 0);
+ assertTrue(TEST_NAME + ": zero size < original, but got " + resultZero,
+ resultZero < initialBufferSize);
assertEquals(TEST_NAME + ": should match resultZero",
resultZero, track.getBufferSizeInFrames());
@@ -118,6 +120,148 @@
track.release();
}
+ // Helper class for tests
+ private static class TestSetup {
+ public int sampleRate = 48000;
+ public int samplesPerFrame = 2;
+ public int bytesPerSample = 2;
+ public int config = AudioFormat.CHANNEL_OUT_STEREO;
+ public int format = AudioFormat.ENCODING_PCM_16BIT;
+ public int mode = AudioTrack.MODE_STREAM;
+ public int streamType = AudioManager.STREAM_MUSIC;
+ public int framesPerBuffer = 256;
+ public double amplitude = 0.5;
+
+ private AudioTrack mTrack;
+ private short[] mData;
+ private int mActualSizeInFrames;
+
+ AudioTrack createTrack() {
+ mData = AudioHelper.createSineWavesShort(framesPerBuffer,
+ samplesPerFrame, 1, amplitude);
+ int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, config, format);
+ // Create a buffer that is 3/2 times bigger than the minimum.
+ // This gives me room to cut it in half and play without glitching.
+ // This is an arbitrary scaling factor.
+ int bufferSize = (minBufferSize * 3) / 2;
+ mTrack = new AudioTrack(streamType, sampleRate, config, format,
+ bufferSize, mode);
+
+ // Calculate and use a smaller buffer size
+ int smallBufferSize = bufferSize / 2; // arbitrary, smaller might underflow
+ int smallBuffSizeInFrames = smallBufferSize / (samplesPerFrame * bytesPerSample);
+ mActualSizeInFrames = mTrack.setBufferSizeInFrames(smallBuffSizeInFrames);
+ return mTrack;
+
+ }
+
+ int primeAudioTrack(String testName) {
+ // Prime the buffer.
+ int samplesWrittenTotal = 0;
+ int samplesWritten;
+ do{
+ samplesWritten = mTrack.write(mData, 0, mData.length);
+ if (samplesWritten > 0) {
+ samplesWrittenTotal += samplesWritten;
+ }
+ } while (samplesWritten == mData.length);
+ int framesWrittenTotal = samplesWrittenTotal / samplesPerFrame;
+ assertTrue(testName + ": framesWrittenTotal = " + framesWrittenTotal
+ + ", size = " + mActualSizeInFrames,
+ framesWrittenTotal >= mActualSizeInFrames);
+ return framesWrittenTotal;
+ }
+
+ /**
+ * @param seconds
+ */
+ public void writeSeconds(double seconds) throws InterruptedException {
+ long msecEnd = System.currentTimeMillis() + (long)(seconds * 1000);
+ while (System.currentTimeMillis() < msecEnd) {
+ // Use non-blocking mode in case the track is hung.
+ int samplesWritten = mTrack.write(mData, 0, mData.length, AudioTrack.WRITE_NON_BLOCKING);
+ if (samplesWritten < mData.length) {
+ int samplesRemaining = mData.length - samplesWritten;
+ int framesRemaining = samplesRemaining / samplesPerFrame;
+ int millis = (framesRemaining * 1000) / sampleRate;
+ Thread.sleep(millis);
+ }
+ }
+ }
+ }
+
+ // Try to play an AudioTrack when the initial size is less than capacity.
+ // We want to make sure the track starts properly and is not stuck.
+ public void testPlaySmallBuffer() throws Exception {
+ final String TEST_NAME = "testPlaySmallBuffer";
+ TestSetup setup = new TestSetup();
+ AudioTrack track = setup.createTrack();
+
+ // Prime the buffer.
+ int framesWrittenTotal = setup.primeAudioTrack(TEST_NAME);
+
+ // Start playing and let it drain.
+ int position1 = track.getPlaybackHeadPosition();
+ assertEquals(TEST_NAME + ": initial position", 0, position1);
+ track.play();
+
+ // Make sure it starts within a reasonably short time.
+ final long MAX_TIME_TO_START_MSEC = 500; // arbitrary
+ long giveUpAt = System.currentTimeMillis() + MAX_TIME_TO_START_MSEC;
+ int position2 = track.getPlaybackHeadPosition();
+ while ((position1 == position2)
+ && (System.currentTimeMillis() < giveUpAt)) {
+ Thread.sleep(20); // arbitrary interval
+ position2 = track.getPlaybackHeadPosition();
+ }
+ assertTrue(TEST_NAME + ": did it start?, position after start = " + position2,
+ position2 > position1);
+
+ // Make sure it finishes playing the data.
+ // Wait several times longer than it should take to play the data.
+ final int several = 3; // arbitrary
+ Thread.sleep(several * framesWrittenTotal * MILLIS_PER_SECOND / setup.sampleRate);
+ position2 = track.getPlaybackHeadPosition();
+ assertEquals(TEST_NAME + ": did it play all the data?",
+ framesWrittenTotal, position2);
+
+ track.release();
+ }
+
+ // Try to play and pause an AudioTrack when the initial size is less than capacity.
+ // We want to make sure the track starts properly and is not stuck.
+ public void testPlayPauseSmallBuffer() throws Exception {
+ final String TEST_NAME = "testPlayPauseSmallBuffer";
+ TestSetup setup = new TestSetup();
+ AudioTrack track = setup.createTrack();
+
+ // Prime the buffer.
+ setup.primeAudioTrack(TEST_NAME);
+
+ // Start playing then pause and play in a loop.
+ int position1 = track.getPlaybackHeadPosition();
+ assertEquals(TEST_NAME + ": initial position", 0, position1);
+ track.play();
+ // try pausing several times to see it if it fails
+ final int several = 4; // arbitrary
+ for (int i = 0; i < several; i++) {
+ // write data in non-blocking mode for a few seconds
+ setup.writeSeconds(2.0); // arbitrary, long enough for audio to get to the device
+ // Did position advance as we were playing? Or was the track stuck?
+ int position2 = track.getPlaybackHeadPosition();
+ int delta = position2 - position1; // safe from wrapping
+ assertTrue(TEST_NAME + ": [" + i + "] did it advance? p1 = " + position1
+ + ", p2 = " + position2, delta > 0);
+ position1 = position2;
+ // pause for a second
+ track.pause();
+ Thread.sleep(MILLIS_PER_SECOND);
+ track.play();
+ }
+
+ track.release();
+ }
+
// Create a track with or without FLAG_LOW_LATENCY
private AudioTrack createCustomAudioTrack(boolean lowLatency) {
final String TEST_NAME = "createCustomAudioTrack";
@@ -303,7 +447,7 @@
// Play with ridiculously small size. We want to get underruns so we know that an app
// can get to the edge of underrunning.
int resultZero = track.setBufferSizeInFrames(0);
- assertTrue(TEST_NAME + ": zero size OK", resultZero > 0);
+ assertTrue(TEST_NAME + ": should return > 0, got " + resultZero, resultZero > 0);
assertTrue(TEST_NAME + ": zero size < original", resultZero < initialBufferSize);
numSeconds = TEST_NUM_SECONDS / 2; // cuz test takes longer when underflowing
numBuffers = numSeconds * TEST_SR / TEST_FRAMES_PER_BUFFER;
diff --git a/tests/tests/media/src/android/media/cts/MediaRouterTest.java b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
new file mode 100644
index 0000000..33544b9
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.content.Context;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteCategory;
+import android.media.MediaRouter.RouteInfo;
+import android.media.MediaRouter.UserRouteInfo;
+import android.test.InstrumentationTestCase;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Test {@link android.media.MediaRouter}.
+ */
+public class MediaRouterTest extends InstrumentationTestCase {
+
+ private MediaRouter mMediaRouter;
+ private RouteCategory mTestCategory;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final Context context = getInstrumentation().getContext();
+ mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ mTestCategory = mMediaRouter.createRouteCategory("testCategory", false);
+ }
+
+ protected void tearDown() throws Exception {
+ mMediaRouter.clearUserRoutes();
+ super.tearDown();
+ }
+
+ public void testSelectRoute() throws Exception {
+ RouteInfo prevSelectedRoute = mMediaRouter.getSelectedRoute(
+ MediaRouter.ROUTE_TYPE_LIVE_AUDIO | MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+ | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+
+ final String newRouteName = "User route's name";
+ UserRouteInfo newRoute = mMediaRouter.createUserRoute(mTestCategory);
+ newRoute.setName(newRouteName);
+ mMediaRouter.addUserRoute(newRoute);
+ mMediaRouter.selectRoute(newRoute.getSupportedTypes(), newRoute);
+
+ RouteInfo nowSelectedRoute = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_USER);
+ assertEquals(newRoute, nowSelectedRoute);
+ assertEquals(mTestCategory, nowSelectedRoute.getCategory());
+
+ mMediaRouter.selectRoute(prevSelectedRoute.getSupportedTypes(), prevSelectedRoute);
+ }
+
+ public void testGetRouteCount() throws Exception {
+ final int count = mMediaRouter.getRouteCount();
+ assertTrue("By default, a media router has at least one route.", count > 0);
+
+ UserRouteInfo userRoute1 = mMediaRouter.createUserRoute(mTestCategory);
+ mMediaRouter.addUserRoute(userRoute1);
+ assertEquals(count + 1, mMediaRouter.getRouteCount());
+
+ mMediaRouter.removeUserRoute(userRoute1);
+ assertEquals(count, mMediaRouter.getRouteCount());
+
+ UserRouteInfo userRoute2 = mMediaRouter.createUserRoute(mTestCategory);
+ mMediaRouter.addUserRoute(userRoute1);
+ mMediaRouter.addUserRoute(userRoute2);
+ assertEquals(count + 2, mMediaRouter.getRouteCount());
+
+ mMediaRouter.clearUserRoutes();
+ assertEquals(count, mMediaRouter.getRouteCount());
+ }
+
+ public void testRouteCategory() throws Exception {
+ final int count = mMediaRouter.getCategoryCount();
+ assertTrue("By default, a media router has at least one route category.", count > 0);
+
+ UserRouteInfo newRoute = mMediaRouter.createUserRoute(mTestCategory);
+ mMediaRouter.addUserRoute(newRoute);
+ assertEquals(count + 1, mMediaRouter.getCategoryCount());
+
+ for (int i = 0; i < mMediaRouter.getCategoryCount(); i++) {
+ if (mMediaRouter.getCategoryAt(i) == mTestCategory) {
+ List<RouteInfo> routesInCategory = new ArrayList<RouteInfo>();
+ mTestCategory.getRoutes(routesInCategory);
+ assertEquals(1, routesInCategory.size());
+
+ RouteInfo route = routesInCategory.get(0);
+ assertEquals(newRoute, route);
+ return;
+ }
+ }
+ assertTrue(false);
+ }
+
+ public void testRouteInfo_getDeviceType() throws Exception {
+ final RouteInfo defaultRoute = mMediaRouter.getDefaultRoute();
+ assertTrue(defaultRoute != null);
+
+ final int deviceType = defaultRoute.getDeviceType();
+ assertEquals(RouteInfo.DEVICE_TYPE_UNKNOWN, deviceType);
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/Utils.java b/tests/tests/media/src/android/media/cts/Utils.java
index bb9cf78..914a0518 100644
--- a/tests/tests/media/src/android/media/cts/Utils.java
+++ b/tests/tests/media/src/android/media/cts/Utils.java
@@ -18,9 +18,13 @@
import android.app.Instrumentation;
import android.app.UiAutomation;
+import android.content.ContentResolver;
+import android.content.Context;
import android.os.ParcelFileDescriptor;
+import android.provider.Settings;
import java.io.FileInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
@@ -67,4 +71,39 @@
result = convertStreamToString(inputStream);
}
}
+
+ protected static void toggleNotificationPolicyAccess(String packageName,
+ Instrumentation instrumentation, boolean on) throws IOException {
+ Context context = instrumentation.getContext();
+
+ // Get permission to enable accessibility
+ UiAutomation uiAutomation = instrumentation.getUiAutomation();
+
+ ContentResolver cr = context.getContentResolver();
+ String alreadyEnabledServices = Settings.Secure.getString(
+ cr, Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+ ParcelFileDescriptor fd = null;
+ if (on) {
+ // Change the settings to enable the media cts package
+ fd = uiAutomation.executeShellCommand(
+ "settings --user cur put secure "
+ + Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES + " "
+ + alreadyEnabledServices + ":"
+ + packageName);
+ } else {
+ int index = alreadyEnabledServices.indexOf(":" + packageName);
+ if (index >= 0) {
+ fd = uiAutomation.executeShellCommand(
+ "settings --user cur put secure "
+ + Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES + " "
+ + alreadyEnabledServices.substring(0, index));
+ }
+ }
+ if (fd != null) {
+ InputStream in = new FileInputStream(fd.getFileDescriptor());
+ byte[] buffer = new byte[4096];
+ while (in.read(buffer) > 0) ;
+ }
+ uiAutomation.destroy();
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index 79b7543..5edee65 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -32,6 +32,7 @@
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
+import android.media.MediaMuxer;
import android.net.Uri;
import android.util.Log;
import android.util.Pair;
@@ -39,9 +40,12 @@
import android.util.Size;
import android.view.Surface;
+import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -168,9 +172,20 @@
abstract class VideoProcessorBase extends MediaCodec.Callback {
private static final String TAG = "VideoProcessorBase";
+ /*
+ * Set this to true to save the encoding results to /data/local/tmp
+ * You will need to make /data/local/tmp writeable, run "setenforce 0",
+ * and remove files left from a previous run.
+ */
+ private boolean mSaveResults = false;
+ private static final String FILE_DIR = "/data/local/tmp";
+ protected int mMuxIndex = -1;
+
+ protected String mProcessorName = "VideoProcessor";
private MediaExtractor mExtractor;
+ protected MediaMuxer mMuxer;
private ByteBuffer mBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE);
- private int mTrackIndex = -1;
+ protected int mTrackIndex = -1;
private boolean mSignaledDecoderEOS;
protected boolean mCompleted;
@@ -185,6 +200,21 @@
protected int mFrameRate = 0;
protected int mBitRate = 0;
+ protected Function<MediaFormat, Boolean> mUpdateConfigFormatHook;
+ protected Function<MediaFormat, Boolean> mCheckOutputFormatHook;
+
+ public void setProcessorName(String name) {
+ mProcessorName = name;
+ }
+
+ public void setUpdateConfigHook(Function<MediaFormat, Boolean> hook) {
+ mUpdateConfigFormatHook = hook;
+ }
+
+ public void setCheckOutputFormatHook(Function<MediaFormat, Boolean> hook) {
+ mCheckOutputFormatHook = hook;
+ }
+
protected void open(String path) throws IOException {
mExtractor = new MediaExtractor();
if (path.startsWith("android.resource://")) {
@@ -209,8 +239,8 @@
// returns true if encoder supports the size
protected boolean initCodecsAndConfigureEncoder(
- String videoEncName, String outMime, int width, int height, int colorFormat)
- throws IOException {
+ String videoEncName, String outMime, int width, int height,
+ int colorFormat) throws IOException {
mDecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
@@ -230,7 +260,7 @@
}
MediaFormat outFmt = MediaFormat.createVideoFormat(outMime, width, height);
-
+ int bitRate = 0;
{
int maxWidth = encCaps.getSupportedWidths().getUpper();
int maxHeight = encCaps.getSupportedHeightsFor(maxWidth).getUpper();
@@ -243,7 +273,7 @@
}
outFmt.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
- int bitRate = mBitRate;
+ bitRate = mBitRate;
if (bitRate <= 0) {
bitRate = encCaps.getBitrateRange().clamp(
(int)(encCaps.getBitrateRange().getUpper() /
@@ -255,8 +285,31 @@
}
outFmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
outFmt.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+ // Some extra configure before starting the encoder.
+ if (mUpdateConfigFormatHook != null) {
+ if (!mUpdateConfigFormatHook.apply(outFmt)) {
+ return false;
+ }
+ }
mEncoder.configure(outFmt, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Log.i(TAG, "encoder input format " + mEncoder.getInputFormat() + " from " + outFmt);
+ if (mSaveResults) {
+ try {
+ String outFileName =
+ FILE_DIR + mProcessorName + "_" + bitRate + "bps";
+ if (outMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) ||
+ outMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+ mMuxer = new MediaMuxer(
+ outFileName + ".webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+ } else {
+ mMuxer = new MediaMuxer(
+ outFileName + ".mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ }
+ // The track can't be added until we have the codec specific data
+ } catch (Exception e) {
+ Log.i(TAG, "couldn't create muxer: " + e);
+ }
+ }
return true;
}
@@ -273,6 +326,11 @@
mExtractor.release();
mExtractor = null;
}
+ if (mMuxer != null) {
+ mMuxer.stop();
+ mMuxer.release();
+ mMuxer = null;
+ }
}
// returns true if filled buffer
@@ -314,7 +372,16 @@
if (DEBUG) Log.v(TAG, "encoder received output #" + ix
+ " (sz=" + info.size + ", f=" + info.flags
+ ", ts=" + info.presentationTimeUs + ")");
- mEncodedStream.addBuffer(mEncoder.getOutputBuffer(ix), info);
+ ByteBuffer outputBuffer = mEncoder.getOutputBuffer(ix);
+ mEncodedStream.addBuffer(outputBuffer, info);
+
+ if (mMuxer != null) {
+ // reset position as addBuffer() modifies it
+ outputBuffer.position(info.offset);
+ outputBuffer.limit(info.offset + info.size);
+ mMuxer.writeSampleData(mMuxIndex, outputBuffer, info);
+ }
+
if (!mCompleted) {
mEncoder.releaseOutputBuffer(ix, false);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
@@ -333,6 +400,15 @@
protected void saveEncoderFormat(MediaFormat format) {
mEncodedStream.setFormat(format);
+ if (mCheckOutputFormatHook != null) {
+ mCheckOutputFormatHook.apply(format);
+ }
+ if (mMuxer != null) {
+ if (mMuxIndex < 0) {
+ mMuxIndex = mMuxer.addTrack(format);
+ mMuxer.start();
+ }
+ }
}
public void playBack(Surface surface) {
@@ -770,7 +846,8 @@
class Encoder {
final private String mName;
final private String mMime;
- final private VideoCapabilities mCaps;
+ final private CodecCapabilities mCaps;
+ final private VideoCapabilities mVideoCaps;
final private Map<Size, Set<Size>> mMinMax; // extreme sizes
final private Map<Size, Set<Size>> mNearMinMax; // sizes near extreme
@@ -784,7 +861,8 @@
Encoder(String name, String mime, CodecCapabilities caps) {
mName = name;
mMime = mime;
- mCaps = caps.getVideoCapabilities();
+ mCaps = caps;
+ mVideoCaps = caps.getVideoCapabilities();
/* calculate min/max sizes */
mMinMax = new HashMap<Size, Set<Size>>();
@@ -793,8 +871,8 @@
mArbitraryH = new HashSet<Size>();
mSizes = new HashSet<Size>();
- xAlign = mCaps.getWidthAlignment();
- yAlign = mCaps.getHeightAlignment();
+ xAlign = mVideoCaps.getWidthAlignment();
+ yAlign = mVideoCaps.getHeightAlignment();
initializeSizes();
}
@@ -811,16 +889,16 @@
int j = ((7 * i) % 11) + 1;
int width, height;
try {
- width = alignedPointInRange(i * 0.125, xAlign, mCaps.getSupportedWidths());
+ width = alignedPointInRange(i * 0.125, xAlign, mVideoCaps.getSupportedWidths());
height = alignedPointInRange(
- j * 0.077, yAlign, mCaps.getSupportedHeightsFor(width));
+ j * 0.077, yAlign, mVideoCaps.getSupportedHeightsFor(width));
mArbitraryW.add(new Size(width, height));
} catch (IllegalArgumentException e) {
}
try {
- height = alignedPointInRange(i * 0.125, yAlign, mCaps.getSupportedHeights());
- width = alignedPointInRange(j * 0.077, xAlign, mCaps.getSupportedWidthsFor(height));
+ height = alignedPointInRange(i * 0.125, yAlign, mVideoCaps.getSupportedHeights());
+ width = alignedPointInRange(j * 0.077, xAlign, mVideoCaps.getSupportedWidthsFor(height));
mArbitraryH.add(new Size(width, height));
} catch (IllegalArgumentException e) {
}
@@ -841,34 +919,34 @@
for (int dy = 0; dy <= yAlign; dy += yAlign) {
Set<Size> bucket = (dx + dy == 0) ? minMax : nearMinMax;
try {
- int width = getExtreme(mCaps.getSupportedWidths(), x, dx);
- int height = getExtreme(mCaps.getSupportedHeightsFor(width), y, dy);
+ int width = getExtreme(mVideoCaps.getSupportedWidths(), x, dx);
+ int height = getExtreme(mVideoCaps.getSupportedHeightsFor(width), y, dy);
bucket.add(new Size(width, height));
// try max max with more reasonable ratio if too skewed
if (x + y == 2 && width >= 4 * height) {
Size wideScreen = getLargestSizeForRatio(16, 9);
width = getExtreme(
- mCaps.getSupportedWidths()
+ mVideoCaps.getSupportedWidths()
.intersect(0, wideScreen.getWidth()), x, dx);
- height = getExtreme(mCaps.getSupportedHeightsFor(width), y, 0);
+ height = getExtreme(mVideoCaps.getSupportedHeightsFor(width), y, 0);
bucket.add(new Size(width, height));
}
} catch (IllegalArgumentException e) {
}
try {
- int height = getExtreme(mCaps.getSupportedHeights(), y, dy);
- int width = getExtreme(mCaps.getSupportedWidthsFor(height), x, dx);
+ int height = getExtreme(mVideoCaps.getSupportedHeights(), y, dy);
+ int width = getExtreme(mVideoCaps.getSupportedWidthsFor(height), x, dx);
bucket.add(new Size(width, height));
// try max max with more reasonable ratio if too skewed
if (x + y == 2 && height >= 4 * width) {
Size wideScreen = getLargestSizeForRatio(9, 16);
height = getExtreme(
- mCaps.getSupportedHeights()
+ mVideoCaps.getSupportedHeights()
.intersect(0, wideScreen.getHeight()), y, dy);
- width = getExtreme(mCaps.getSupportedWidthsFor(height), x, dx);
+ width = getExtreme(mVideoCaps.getSupportedWidthsFor(height), x, dx);
bucket.add(new Size(width, height));
}
} catch (IllegalArgumentException e) {
@@ -907,17 +985,17 @@
}
private Size getLargestSizeForRatio(int x, int y) {
- Range<Integer> widthRange = mCaps.getSupportedWidths();
- Range<Integer> heightRange = mCaps.getSupportedHeightsFor(widthRange.getUpper());
- final int xAlign = mCaps.getWidthAlignment();
- final int yAlign = mCaps.getHeightAlignment();
+ Range<Integer> widthRange = mVideoCaps.getSupportedWidths();
+ Range<Integer> heightRange = mVideoCaps.getSupportedHeightsFor(widthRange.getUpper());
+ final int xAlign = mVideoCaps.getWidthAlignment();
+ final int yAlign = mVideoCaps.getHeightAlignment();
// scale by alignment
int width = alignInRange(
Math.sqrt(widthRange.getUpper() * heightRange.getUpper() * (double)x / y),
xAlign, widthRange);
int height = alignInRange(
- width * (double)y / x, yAlign, mCaps.getSupportedHeightsFor(width));
+ width * (double)y / x, yAlign, mVideoCaps.getSupportedHeightsFor(width));
return new Size(width, height);
}
@@ -950,22 +1028,87 @@
return test(width, height, true /* optional */, flexYUV);
}
+ public boolean testIntraRefresh(int width, int height) {
+ final int refreshPeriod = 10;
+ if (!mCaps.isFeatureSupported(CodecCapabilities.FEATURE_IntraRefresh)) {
+ return false;
+ }
+
+ Function<MediaFormat, Boolean> updateConfigFormatHook =
+ new Function<MediaFormat, Boolean>() {
+ public Boolean apply(MediaFormat fmt) {
+ // set i-frame-interval to 10000 so encoded video only has 1 i-frame.
+ fmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10000);
+ fmt.setInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD, refreshPeriod);
+ return true;
+ }
+ };
+
+ Function<MediaFormat, Boolean> checkOutputFormatHook =
+ new Function<MediaFormat, Boolean>() {
+ public Boolean apply(MediaFormat fmt) {
+ int intraPeriod = fmt.getInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD);
+ // Make sure intra period is correct and carried in the output format.
+ // intraPeriod must be larger than 0 and not larger than what has been set.
+ if (intraPeriod > refreshPeriod) {
+ throw new RuntimeException("Intra period mismatch");
+ }
+ return true;
+ }
+ };
+
+ String testName =
+ mName + '_' + width + "x" + height + '_' + "flexYUV_intraRefresh";
+
+ Consumer<VideoProcessorBase> configureVideoProcessor =
+ new Consumer<VideoProcessorBase>() {
+ public void accept(VideoProcessorBase processor) {
+ processor.setProcessorName(testName);
+ processor.setUpdateConfigHook(updateConfigFormatHook);
+ processor.setCheckOutputFormatHook(checkOutputFormatHook);
+ }
+ };
+
+ return test(width, height, 0 /* frameRate */, 0 /* bitRate */, true /* optional */,
+ true /* flex */, configureVideoProcessor);
+ }
+
public boolean testDetailed(
int width, int height, int frameRate, int bitRate, boolean flexYUV) {
- return test(width, height, frameRate, bitRate, true /* optional */, flexYUV);
+ String testName =
+ mName + '_' + width + "x" + height + '_' + (flexYUV ? "flexYUV" : " surface");
+ Consumer<VideoProcessorBase> configureVideoProcessor =
+ new Consumer<VideoProcessorBase>() {
+ public void accept(VideoProcessorBase processor) {
+ processor.setProcessorName(testName);
+ }
+ };
+ return test(width, height, frameRate, bitRate, true /* optional */, flexYUV,
+ configureVideoProcessor);
}
public boolean testSupport(int width, int height, int frameRate, int bitRate) {
- return mCaps.areSizeAndRateSupported(width, height, frameRate) &&
- mCaps.getBitrateRange().contains(bitRate);
+ return mVideoCaps.areSizeAndRateSupported(width, height, frameRate) &&
+ mVideoCaps.getBitrateRange().contains(bitRate);
}
- private boolean test(int width, int height, boolean optional, boolean flexYUV) {
- return test(width, height, 0 /* frameRate */, 0 /* bitRate */, optional, flexYUV);
+ private boolean test(
+ int width, int height, boolean optional, boolean flexYUV) {
+ String testName =
+ mName + '_' + width + "x" + height + '_' + (flexYUV ? "flexYUV" : " surface");
+ Consumer<VideoProcessorBase> configureVideoProcessor =
+ new Consumer<VideoProcessorBase>() {
+ public void accept(VideoProcessorBase processor) {
+ processor.setProcessorName(testName);
+ }
+ };
+ return test(width, height, 0 /* frameRate */, 0 /* bitRate */,
+ optional, flexYUV, configureVideoProcessor);
}
- private boolean test(int width, int height, int frameRate, int bitRate,
- boolean optional, boolean flexYUV) {
+ private boolean test(
+ int width, int height, int frameRate, int bitRate, boolean optional,
+ boolean flexYUV, Consumer<VideoProcessorBase> configureVideoProcessor) {
Log.i(TAG, "testing " + mMime + " on " + mName + " for " + width + "x" + height
+ (flexYUV ? " flexYUV" : " surface"));
@@ -973,6 +1116,7 @@
flexYUV ? new VideoProcessor() : new SurfaceVideoProcessor();
processor.setFrameAndBitRates(frameRate, bitRate);
+ configureVideoProcessor.accept(processor);
// We are using a resource URL as an example
boolean success = processor.processLoop(
@@ -1409,6 +1553,46 @@
public void testOtherVP9Flex1080p() { specific(otherVP9(), 1920, 1080, true /* flex */); }
public void testOtherVP9Surf1080p() { specific(otherVP9(), 1920, 1080, false /* flex */); }
+ public void testGoogH265Flex360pWithIntraRefresh() {
+ intraRefresh(googH265(), 480, 360);
+ }
+
+ public void testGoogH264Flex360pWithIntraRefresh() {
+ intraRefresh(googH264(), 480, 360);
+ }
+
+ public void testGoogH263Flex360pWithIntraRefresh() {
+ intraRefresh(googH263(), 480, 360);
+ }
+
+ public void testGoogMpeg4Flex360pWithIntraRefresh() {
+ intraRefresh(googMpeg4(), 480, 360);
+ }
+
+ public void testGoogVP8Flex360pWithIntraRefresh() {
+ intraRefresh(googVP8(), 480, 360);
+ }
+
+ public void testOtherH265Flex360pWithIntraRefresh() {
+ intraRefresh(otherH265(), 480, 360);
+ }
+
+ public void testOtherH264Flex360pWithIntraRefresh() {
+ intraRefresh(otherH264(), 480, 360);
+ }
+
+ public void testOtherH263FlexQCIFWithIntraRefresh() {
+ intraRefresh(otherH263(), 176, 120);
+ }
+
+ public void testOtherMpeg4Flex360pWithIntraRefresh() {
+ intraRefresh(otherMpeg4(), 480, 360);
+ }
+
+ public void testOtherVP8Flex360pWithIntraRefresh() {
+ intraRefresh(otherVP8(), 480, 360);
+ }
+
// Tests encoder profiles required by CDD.
// H264
public void testH264LowQualitySDSupport() {
@@ -1581,6 +1765,23 @@
}
}
+ /* test intra refresh with flexYUV */
+ private void intraRefresh(Encoder[] encoders, int width, int height) {
+ boolean skipped = true;
+ if (encoders.length == 0) {
+ MediaUtils.skipTest("no such encoder present");
+ return;
+ }
+ for (Encoder encoder : encoders) {
+ if (encoder.testIntraRefresh(width, height)) {
+ skipped = false;
+ }
+ }
+ if (skipped) {
+ MediaUtils.skipTest("intra-refresh unsupported");
+ }
+ }
+
/* test size, frame rate and bit rate */
private void detailed(
Encoder[] encoders, int width, int height, int frameRate, int bitRate,
diff --git a/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java b/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
index 35d4bbd..7254045 100644
--- a/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
+++ b/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
@@ -18,14 +18,11 @@
import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
import com.android.compatibility.common.util.DynamicConfigHostSide;
import com.android.ddmlib.IDevice;
-import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.util.FileUtil;
@@ -150,7 +147,7 @@
if(!matcher.find()) {
// could not find resolution in dumpsysOutput, return largest max playback resolution
// so that preparer copies all media files
- CLog.e(MAX_PLAYBACK_RES_FAILURE_MSG);
+ logError(MAX_PLAYBACK_RES_FAILURE_MSG);
return resolutions[RES_1920_1080];
}
@@ -160,7 +157,7 @@
first = Integer.parseInt(matcher.group(1));
second = Integer.parseInt(matcher.group(2));
} catch (NumberFormatException e) {
- CLog.e(MAX_PLAYBACK_RES_FAILURE_MSG);
+ logError(MAX_PLAYBACK_RES_FAILURE_MSG);
return resolutions[RES_1920_1080];
}
// dimensions in dumpsys output seem consistently reversed
@@ -195,11 +192,6 @@
return true;
}
- /* A simple helper to print messages to the tradefed console */
- private static void printInfo(String info) {
- LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, info);
- }
-
/*
* After downloading and unzipping the media files, mLocalMediaPath must be the path to the
* directory containing 'bbb_short' and 'bbb_full' directories, as it is defined in its
@@ -249,7 +241,7 @@
new BufferedOutputStream(new FileOutputStream(mediaFolderZip));
byte[] buffer = new byte[1024];
int count;
- printInfo("Downloading media files to host");
+ logInfo("Downloading media files to host");
while ((count = in.read(buffer)) >= 0) {
out.write(buffer, 0, count);
}
@@ -257,7 +249,7 @@
out.close();
in.close();
- printInfo("Unzipping media files");
+ logInfo("Unzipping media files");
ZipUtil.extractZip(new ZipFile(mediaFolderZip), mediaFolder);
} catch (IOException e) {
@@ -283,16 +275,15 @@
Dimension copiedResolution = resolutions[resIndex];
String resString = resolutionString(copiedResolution);
if (copiedResolution.width > mvpr.width || copiedResolution.height > mvpr.height) {
- printInfo(String.format(
- "Device cannot support resolutions %s and larger, media copying complete",
- resString));
+ logInfo("Device cannot support resolutions %s and larger, media copying complete",
+ resString);
return;
}
String deviceShortFilePath = baseDeviceShortDir + resString;
String deviceFullFilePath = baseDeviceFullDir + resString;
if (!device.doesFileExist(deviceShortFilePath) ||
!device.doesFileExist(deviceFullFilePath)) {
- printInfo(String.format("Copying files of resolution %s to device", resString));
+ logInfo("Copying files of resolution %s to device", resString);
String localShortDirName = "bbb_short/" + resString;
String localFullDirName = "bbb_full/" + resString;
File localShortDir = new File(mLocalMediaPath, localShortDirName);
@@ -330,7 +321,7 @@
Dimension mvpr = getMaxVideoPlaybackResolution(device);
if (mediaFilesExistOnDevice(device, mvpr)) {
// if files already on device, do nothing
- printInfo("Media files found on the device");
+ logInfo("Media files found on the device");
return;
}
@@ -356,7 +347,7 @@
updateLocalMediaPath(mediaFolder);
}
- printInfo(String.format("Media files located on host at: %s", mLocalMediaPath));
+ logInfo("Media files located on host at: %s", mLocalMediaPath);
copyMediaFiles(device, mvpr);
}
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
index 6f4ebdd..b33451b 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
-import android.media.CamcorderProfile;
import android.cts.util.MediaUtils;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.VideoEncoder;
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java
index a37d4c2..ca935c4 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java
@@ -20,7 +20,6 @@
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.SurfaceTexture;
-import android.media.CamcorderProfile;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
@@ -34,7 +33,7 @@
import junit.framework.Assert;
public class NativeMediaActivity extends Activity implements OnSurfaceChangedListener {
- public static final String EXTRA_VIDEO_QUALITY = "videoQuality";
+ public static final String EXTRA_VIDEO_HEIGHT = "videoHeight";
// should be long enough. time-out can be treated as error
public static final long NATIVE_MEDIA_LIFECYCLE_TIMEOUT_MS = 10000;
static final String TAG = "NativeMedia";
@@ -51,8 +50,7 @@
private SurfaceTextureGLSurfaceView mGLView;
private volatile boolean mNativeCreated = false;
- /** 0 for default (480x360), other value can be CamcorderProfile.QUALITY_480P / 720P / 1080P */
- private int mVideoQuality = 0;
+ private int mVideoHeight = 360;
// native media status queued whenever there is a change in life.
private final BlockingQueue<Boolean> mNativeWaitQ = new LinkedBlockingQueue<Boolean>();
@@ -61,7 +59,7 @@
super.onCreate(icicle);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- mVideoQuality = getIntent().getIntExtra(EXTRA_VIDEO_QUALITY, mVideoQuality);
+ mVideoHeight = getIntent().getIntExtra(EXTRA_VIDEO_HEIGHT, mVideoHeight);
mGLView = new SurfaceTextureGLSurfaceView(this, this);
setContentView(mGLView);
}
@@ -159,14 +157,14 @@
private String getMediaString() {
int mediaIndex = 0; // default: 480x360
- switch(mVideoQuality) {
- case CamcorderProfile.QUALITY_1080P:
+ switch(mVideoHeight) {
+ case 1080:
mediaIndex = 3;
break;
- case CamcorderProfile.QUALITY_720P:
+ case 720:
mediaIndex = 2;
break;
- case CamcorderProfile.QUALITY_480P:
+ case 480:
mediaIndex = 1;
break;
}
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
index 05145f5..40284a6 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
@@ -18,7 +18,6 @@
import android.app.Instrumentation;
import android.content.Intent;
import android.cts.util.MediaUtils;
-import android.media.CamcorderProfile;
import android.media.MediaFormat;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.VideoEncoder;
@@ -40,37 +39,30 @@
}
public void test1080pPlay() throws InterruptedException {
- runPlayTest(CamcorderProfile.QUALITY_1080P);
+ runPlayTest(1920, 1080);
}
public void test720pPlay() throws InterruptedException {
- runPlayTest(CamcorderProfile.QUALITY_720P);
+ runPlayTest(1280, 720);
}
public void test480pPlay() throws InterruptedException {
- runPlayTest(CamcorderProfile.QUALITY_480P);
+ runPlayTest(720, 480);
}
public void testDefaultPlay() throws InterruptedException {
- runPlayTest(0);
+ runPlayTest(480, 360);
}
- private void runPlayTest(int quality) throws InterruptedException {
+ private void runPlayTest(int width, int height) throws InterruptedException {
+ MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, width, height);
// Don't run the test if the codec isn't supported.
- if (!MediaUtils.checkDecoder(MIME_TYPE)) {
+ if (!MediaUtils.canDecode(format)) {
return; // skip
}
- // Don't run the test if the quality level isn't supported.
- if (quality != 0) {
- if (!isResolutionSupported(quality)) {
- Log.w(TAG, "Quality level " + quality + " not supported.");
- return;
- }
- }
Intent intent = new Intent();
- intent.putExtra(NativeMediaActivity.EXTRA_VIDEO_QUALITY,
- quality);
+ intent.putExtra(NativeMediaActivity.EXTRA_VIDEO_HEIGHT, height);
setActivityIntent(intent);
final NativeMediaActivity activity = getActivity();
final Instrumentation instrumentation = getInstrumentation();
@@ -98,17 +90,4 @@
Assert.assertNotNull(status); // null means time-out
Assert.assertEquals(expectAlive, status.booleanValue());
}
-
- private boolean isResolutionSupported(int quality) {
- Assert.assertEquals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED);
- if (!CamcorderProfile.hasProfile(quality)) {
- return false;
- }
- CamcorderProfile profile = CamcorderProfile.get(quality);
- if ((profile != null) && (profile.videoCodec == VIDEO_CODEC) &&
- (profile.audioCodec == AudioEncoder.AAC)) {
- return true;
- }
- return false;
- }
}
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
index 8019823..e782994 100644
--- a/tests/tests/nativemedia/sl/Android.mk
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -51,6 +51,8 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_CFLAGS := -Werror -Wall
+
include $(BUILD_CTS_EXECUTABLE)
include $(CLEAR_VARS)
@@ -64,6 +66,7 @@
LOCAL_CFLAGS := \
-DBUILD_ONLY \
+ -Werror -Wall
LOCAL_SHARED_LIBRARIES := \
liblog \
diff --git a/tests/tests/net/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
index 2bc8216..f8daabf 100644
--- a/tests/tests/net/AndroidManifest.xml
+++ b/tests/tests/net/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/net/src/android/net/cts/AirplaneModeTest.java b/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
new file mode 100644
index 0000000..0a3146c
--- /dev/null
+++ b/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.net.cts;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.lang.Thread;
+
+public class AirplaneModeTest extends AndroidTestCase {
+ private static final String TAG = "AirplaneModeTest";
+ private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
+ private static final String FEATURE_WIFI = "android.hardware.wifi";
+ private static final int TIMEOUT_MS = 10 * 1000;
+ private boolean mHasFeature;
+ private Context mContext;
+ private ContentResolver resolver;
+
+ public void setup() {
+ mContext= getContext();
+ resolver = mContext.getContentResolver();
+ mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH)
+ || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
+ }
+
+ public void testAirplaneMode() {
+ setup();
+ if (!mHasFeature) {
+ Log.i(TAG, "The device doesn't support network bluetooth or wifi feature");
+ return;
+ }
+
+ for (int testCount = 0; testCount < 2; testCount++) {
+ if (!doOneTest()) {
+ fail("Airplane mode failed to change in " + TIMEOUT_MS + "msec");
+ return;
+ }
+ }
+ }
+
+ private boolean doOneTest() {
+ boolean airplaneModeOn = isAirplaneModeOn();
+ setAirplaneModeOn(!airplaneModeOn);
+
+ try {
+ Thread.sleep(TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Sleep time interrupted.", e);
+ }
+
+ if (airplaneModeOn == isAirplaneModeOn()) {
+ return false;
+ }
+ return true;
+ }
+
+ private void setAirplaneModeOn(boolean enabling) {
+ // Change the system setting for airplane mode
+ Settings.Global.putInt(resolver, Settings.Global.AIRPLANE_MODE_ON, enabling ? 1 : 0);
+ }
+
+ private boolean isAirplaneModeOn() {
+ // Read the system setting for airplane mode
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+}
diff --git a/tests/tests/net/src/android/net/cts/TheaterModeTest.java b/tests/tests/net/src/android/net/cts/TheaterModeTest.java
new file mode 100644
index 0000000..10fca6f
--- /dev/null
+++ b/tests/tests/net/src/android/net/cts/TheaterModeTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.net.cts;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.lang.Thread;
+
+public class TheaterModeTest extends AndroidTestCase {
+ private static final String TAG = "TheaterModeTest";
+ private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
+ private static final String FEATURE_WIFI = "android.hardware.wifi";
+ private static final int TIMEOUT_MS = 10 * 1000;
+ private boolean mHasFeature;
+ private Context mContext;
+ private ContentResolver resolver;
+
+ public void setup() {
+ mContext= getContext();
+ resolver = mContext.getContentResolver();
+ mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH)
+ || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
+ }
+
+ public void testTheaterMode() {
+ setup();
+ if (!mHasFeature) {
+ Log.i(TAG, "The device doesn't support network bluetooth or wifi feature");
+ return;
+ }
+
+ for (int testCount = 0; testCount < 2; testCount++) {
+ if (!doOneTest()) {
+ fail("Theater mode failed to change in " + TIMEOUT_MS + "msec");
+ return;
+ }
+ }
+ }
+
+ private boolean doOneTest() {
+ boolean theaterModeOn = isTheaterModeOn();
+
+ setTheaterModeOn(!theaterModeOn);
+ try {
+ Thread.sleep(TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Sleep time interrupted.", e);
+ }
+
+ if (theaterModeOn == isTheaterModeOn()) {
+ return false;
+ }
+ return true;
+ }
+
+ private void setTheaterModeOn(boolean enabling) {
+ // Change the system setting for theater mode
+ Settings.Global.putInt(resolver, Settings.Global.THEATER_MODE_ON, enabling ? 1 : 0);
+ }
+
+ private boolean isTheaterModeOn() {
+ // Read the system setting for theater mode
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.THEATER_MODE_ON, 0) != 0;
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 4478bd4..897e5cf 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -296,6 +296,8 @@
for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) {
startScan();
// Make sure at least one AP is found.
+ assertTrue("mScanResult should not be null. This may be due to a scan timeout",
+ mScanResults != null);
assertFalse("empty scan results!", mScanResults.isEmpty());
long nowMillis = SystemClock.elapsedRealtime();
// Keep track of how many APs are fresh in one scan.
@@ -373,7 +375,7 @@
assertTrue(notExist != pos);
// Enable & disable network
- boolean disableOthers = false;
+ boolean disableOthers = true;
assertTrue(mWifiManager.enableNetwork(netId, disableOthers));
wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
assertDisableOthers(wifiConfiguration, disableOthers);
@@ -484,6 +486,9 @@
}
assertTrue(mWifiManager.isWifiEnabled());
+ // This will generate a distinct stack trace if the initial connection fails.
+ connectWifi();
+
int i = 0;
for (; i < 15; i++) {
// Wait for a WiFi connection
diff --git a/tests/tests/automotive/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
similarity index 73%
copy from tests/tests/automotive/Android.mk
copy to tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
index abef2ac..df29b5f 100644
--- a/tests/tests/automotive/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
@@ -11,28 +11,24 @@
# 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)
+#
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := CtsNetSecConfigCleartextTrafficTestCases
-LOCAL_PACKAGE_NAME := CtsAutomotiveTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
+LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
-
-LOCAL_JAVA_LIBRARIES := android.car
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res/
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
LOCAL_SDK_VERSION := current
-
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
new file mode 100644
index 0000000..dbb4770
--- /dev/null
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/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.security.net.config.cts.CtsNetSecConfigCleartextTrafficTestCases">
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" />
+ </application>
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.net.config.cts.CtsNetSecConfigCleartextTrafficTestCases"
+ android:label="">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
diff --git a/tests/tests/automotive/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml
similarity index 75%
copy from tests/tests/automotive/AndroidTest.xml
copy to tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml
index b4af1f5..9957342 100644
--- a/tests/tests/automotive/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml
@@ -13,12 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for CTS Automotive test cases">
+<configuration description="Config for CTS CtsNetSecConfigCleartextTraffic test cases">
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsAutomotiveTestCases.apk" />
+ <option name="test-file-name" value="CtsNetSecConfigCleartextTrafficTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.support.car.cts" />
+ <option name="package" value="android.security.net.config.cts.CtsNetSecConfigCleartextTrafficTestCases" />
</test>
</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/res/xml/network_security_config.xml b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/res/xml/network_security_config.xml
new file mode 100644
index 0000000..987b178
--- /dev/null
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/res/xml/network_security_config.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="false">
+ <domain includeSubdomains="true">android.com</domain>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain>developer.android.com</domain>
+ </domain-config>
+ </domain-config>
+</network-security-config>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/src/android/security/net/config/cts/CleartextPermittedTest.java b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/src/android/security/net/config/cts/CleartextPermittedTest.java
new file mode 100644
index 0000000..401b5ac
--- /dev/null
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/src/android/security/net/config/cts/CleartextPermittedTest.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 android.security.net.config.cts;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.X509TrustManager;
+import junit.framework.TestCase;
+
+public class CleartextPermittedTest extends TestCase {
+ public void testDefaultAllowed() throws Exception {
+ TestUtils.assertCleartextConnectionSucceeds("google.com", 80);
+ TestUtils.assertTlsConnectionSucceeds("google.com", 443);
+ }
+
+ public void testCleartextBlocked() throws Exception {
+ TestUtils.assertCleartextConnectionFails("android.com", 80);
+ TestUtils.assertTlsConnectionSucceeds("android.com", 443);
+ // subdomains of android.com are also disallowed.
+ TestUtils.assertCleartextConnectionFails("www.android.com", 80);
+ TestUtils.assertTlsConnectionSucceeds("www.android.com", 443);
+ }
+
+ public void testNestedCleartextPermitted() throws Exception {
+ // developer.android.com is explicitly permitted.
+ TestUtils.assertCleartextConnectionSucceeds("developer.android.com", 80);
+ TestUtils.assertTlsConnectionSucceeds("developer.android.com", 443);
+ }
+}
diff --git a/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java b/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java
index 0952cd3..d114ab5 100644
--- a/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java
+++ b/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java
@@ -20,6 +20,7 @@
import java.io.InputStream;
import java.io.IOException;
+import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.security.KeyStore;
@@ -28,7 +29,6 @@
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.ArrayList;
-import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
@@ -45,17 +45,26 @@
private TestUtils() {
}
-
public static void assertTlsConnectionSucceeds(String host, int port) throws Exception {
assertSslSocketSucceeds(host, port);
- assertHttpClientHttpsSucceeds(host, port);
- assertUrlConnectionHttpsSucceeds(host, port);
+ assertHttpClientSucceeds(host, port, true /* https */);
+ assertUrlConnectionSucceeds(host, port, true /* https */);
}
public static void assertTlsConnectionFails(String host, int port) throws Exception {
assertSslSocketFails(host, port);
- assertHttpClientHttpsFails(host, port);
- assertUrlConnectionHttpsFails(host, port);
+ assertHttpClientFails(host, port, true /* https */);
+ assertUrlConnectionFails(host, port, true /* https */);
+ }
+
+ public static void assertCleartextConnectionSucceeds(String host, int port) throws Exception {
+ assertHttpClientSucceeds(host, port, false /* http */);
+ assertUrlConnectionSucceeds(host, port, false /* http */);
+ }
+
+ public static void assertCleartextConnectionFails(String host, int port) throws Exception {
+ assertHttpClientFails(host, port, false /* http */);
+ assertUrlConnectionFails(host, port, false /* http */);
}
public static X509TrustManager getDefaultTrustManager() throws Exception {
@@ -95,26 +104,27 @@
s.getInputStream();
}
- private static void assertUrlConnectionHttpsFails(String host, int port)
+ private static void assertUrlConnectionFails(String host, int port, boolean https)
throws Exception {
- URL url = new URL("https://" + host + ":" + port);
- HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ URL url = new URL((https ? "https://" : "http://") + host + ":" + port);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
connection.getInputStream();
fail("Connection to " + host + ":" + port + " succeeded");
- } catch (SSLHandshakeException expected) {
+ } catch (IOException expected) {
}
}
- private static void assertUrlConnectionHttpsSucceeds(String host, int port)
+ private static void assertUrlConnectionSucceeds(String host, int port, boolean https)
throws Exception {
- URL url = new URL("https://" + host + ":" + port);
- HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ URL url = new URL((https ? "https://" : "http://") + host + ":" + port);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.getInputStream();
}
- private static void assertHttpClientHttpsSucceeds(String host, int port) throws Exception {
- URL url = new URL("https://" + host + ":" + port);
+ private static void assertHttpClientSucceeds(String host, int port, boolean https)
+ throws Exception {
+ URL url = new URL((https ? "https://" : "http://") + host + ":" + port);
AndroidHttpClient httpClient = AndroidHttpClient.newInstance(null);
try {
HttpResponse response = httpClient.execute(new HttpGet(url.toString()));
@@ -123,8 +133,9 @@
}
}
- private static void assertHttpClientHttpsFails(String host, int port) throws Exception {
- URL url = new URL("https://" + host + ":" + port);
+ private static void assertHttpClientFails(String host, int port, boolean https)
+ throws Exception {
+ URL url = new URL((https ? "https://" : "http://") + host + ":" + port);
AndroidHttpClient httpClient = AndroidHttpClient.newInstance(null);
try {
HttpResponse response = httpClient.execute(new HttpGet(url.toString()));
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index c837ce3..bbee284 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -24,15 +24,17 @@
# Include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner guava
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil ctstestrunner guava platform-test-annotations
LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libctsos_jni libnativehelper_compat_libc++
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- src/android/os/cts/IParcelFileDescriptorPeer.aidl \
- src/android/os/cts/IEmptyService.aidl \
- src/android/os/cts/ISeccompIsolatedService.aidl \
- src/android/os/cts/ISecondary.aidl
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ src/android/os/cts/IParcelFileDescriptorPeer.aidl \
+ src/android/os/cts/IEmptyService.aidl \
+ src/android/os/cts/ISeccompIsolatedService.aidl \
+ src/android/os/cts/ISecondary.aidl
LOCAL_PACKAGE_NAME := CtsOsTestCases
diff --git a/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java b/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java
index bd88073..4c4804e 100644
--- a/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java
+++ b/tests/tests/os/src/android/os/cts/CustomClassLoaderTest.java
@@ -19,6 +19,7 @@
import java.io.*;
import java.lang.reflect.*;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
public class CustomClassLoaderTest extends AndroidTestCase {
@@ -76,6 +77,7 @@
/* Test a custom class loader based on the PathClassLoader.
*/
+ @Presubmit
public void testCustomPathClassLoader() throws Exception {
// Try to load the TestClass class by the CustomPathClassLoader.
try {
diff --git a/tests/tests/os/src/android/os/cts/HardwarePropertiesManagerTest.java b/tests/tests/os/src/android/os/cts/HardwarePropertiesManagerTest.java
deleted file mode 100644
index 4239fa2..0000000
--- a/tests/tests/os/src/android/os/cts/HardwarePropertiesManagerTest.java
+++ /dev/null
@@ -1,145 +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.os.cts;
-
-import android.content.Context;
-import android.os.CpuUsageInfo;
-import android.os.HardwarePropertiesManager;
-import android.os.SystemClock;
-import android.test.AndroidTestCase;
-
-import java.lang.Math;
-
-public class HardwarePropertiesManagerTest extends AndroidTestCase {
- public static final int MAX_FAN_SPEED = 20000;
- public static final int MAX_DEVICE_TEMP = 200;
- public static final int MONITORING_ITERATION_NUMBER = 10;
-
- // Time between checks in milliseconds.
- public static final long SLEEP_TIME = 10;
-
- private void checkFanSpeed(float speed) {
- assertTrue(speed >= 0 && speed < MAX_FAN_SPEED);
- }
-
- private void checkDeviceTemp(float temp) {
- assertTrue(Math.abs(temp) < MAX_DEVICE_TEMP);
- }
-
- private void checkCpuUsageInfo(CpuUsageInfo info) {
- assertTrue(info.getActive() >= 0 && info.getTotal() >= 0 && info.getTotal() >= info.getActive());
- }
-
- private void checkFanSpeeds(float[] fanSpeeds) {
- for (float speed : fanSpeeds) {
- checkFanSpeed(speed);
- }
- }
-
- private void checkTemps(float[] temps) {
- for (float temp : temps) {
- checkDeviceTemp(temp);
- }
- }
-
- private void checkCpuUsages(CpuUsageInfo[] cpuUsages) {
- for (CpuUsageInfo info : cpuUsages) {
- checkCpuUsageInfo(info);
- }
- }
-
- // Check validity of new array of fan speeds:
- // the number of fans should be the same.
- private void checkFanSpeeds(float[] speeds, float[] oldSpeeds) {
- assertEquals(speeds.length, oldSpeeds.length);
- }
-
- // Check validity of new array of device temperatures:
- // the number of entries should be the same.
- private void checkDeviceTemps(float[] temps, float[] oldTemps) {
- assertEquals(temps.length, oldTemps.length);
- }
-
- // Check validity of new array of cpu usages:
- // The number of CPUs should be the same and total/active time should not decrease.
- private void checkCpuUsages(CpuUsageInfo[] infos,
- CpuUsageInfo[] oldInfos) {
- assertEquals(infos.length, oldInfos.length);
- for (int i = 0; i < infos.length; ++i) {
- assertTrue(oldInfos[i].getActive() <= infos[i].getActive() &&
- oldInfos[i].getTotal() <= infos[i].getTotal());
- }
- }
-
- /**
- * test points:
- * 1. Get fan speeds, device temperatures and CPU usage information.
- * 2. Check for validity.
- * 3. Sleep.
- * 4. Do it 10 times and compare with old ones.
- */
- public void testHardwarePropertiesManager() throws InterruptedException {
- HardwarePropertiesManager hm = (HardwarePropertiesManager) getContext().getSystemService(
- Context.HARDWARE_PROPERTIES_SERVICE);
-
- float[] oldFanSpeeds = hm.getFanSpeeds();
- float[] oldCpuTemps = hm.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU);
- float[] oldGpuTemps = hm.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU);
- float[] oldBatteryTemps = hm.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY);
- CpuUsageInfo[] oldCpuUsages = hm.getCpuUsages();
-
- checkFanSpeeds(oldFanSpeeds);
- checkTemps(oldCpuTemps);
- checkTemps(oldGpuTemps);
- checkTemps(oldBatteryTemps);
- checkCpuUsages(oldCpuUsages);
-
- for (int i = 0; i < MONITORING_ITERATION_NUMBER; i++) {
- Thread.sleep(SLEEP_TIME);
-
- float[] fanSpeeds = hm.getFanSpeeds();
- float[] cpuTemps = hm.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU);
- float[] gpuTemps = hm.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU);
- float[] batteryTemps = hm.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY);
- CpuUsageInfo[] cpuUsages = hm.getCpuUsages();
-
- checkFanSpeeds(fanSpeeds);
- checkTemps(cpuTemps);
- checkTemps(gpuTemps);
- checkTemps(batteryTemps);
- checkCpuUsages(cpuUsages);
-
- checkFanSpeeds(fanSpeeds, oldFanSpeeds);
- checkDeviceTemps(cpuTemps, oldCpuTemps);
- checkDeviceTemps(gpuTemps, oldGpuTemps);
- checkDeviceTemps(batteryTemps, oldBatteryTemps);
- checkCpuUsages(cpuUsages, oldCpuUsages);
-
- oldFanSpeeds = fanSpeeds;
- oldCpuTemps = cpuTemps;
- oldGpuTemps = gpuTemps;
- oldBatteryTemps = batteryTemps;
- oldCpuUsages = cpuUsages;
- }
- }
-}
diff --git a/tests/tests/os/src/android/os/cts/SecurityPatchTest.java b/tests/tests/os/src/android/os/cts/SecurityPatchTest.java
index 5516a19..f35af2e 100644
--- a/tests/tests/os/src/android/os/cts/SecurityPatchTest.java
+++ b/tests/tests/os/src/android/os/cts/SecurityPatchTest.java
@@ -32,7 +32,7 @@
private static final String SECURITY_PATCH_DATE_ERROR =
"ro.build.version.security_patch should be \"%d-%02d\" or later. Found \"%s\"";
private static final int SECURITY_PATCH_YEAR = 2016;
- private static final int SECURITY_PATCH_MONTH = 04;
+ private static final int SECURITY_PATCH_MONTH = 05;
private boolean mSkipTests = false;
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index 2de9d9c..c37ddfc 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -29,7 +29,8 @@
LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner guava android-ex-camera2
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctstestrunner guava android-ex-camera2 platform-test-annotations
LOCAL_JNI_SHARED_LIBRARIES := libctspermission_jni libnativehelper_compat_libc++
diff --git a/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java b/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java
index 021a501..e40d7cb 100644
--- a/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/Camera2PermissionTest.java
@@ -23,6 +23,7 @@
import android.hardware.camera2.CameraManager;
import android.os.Handler;
import android.os.HandlerThread;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -96,6 +97,7 @@
/**
* Add and remove availability listeners should work without permission.
*/
+ @Presubmit
public void testAvailabilityCallback() throws Exception {
DummyCameraListener availabilityListener = new DummyCameraListener();
// Remove a not-registered listener is a no-op.
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 00c655e..617f0ab 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -107,7 +107,7 @@
.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
String myAppDirectory = getContext().getApplicationInfo().dataDir;
for (ApplicationInfo app : apps) {
- if (!myAppDirectory.equals(app.dataDir)) {
+ if (app.dataDir != null && !myAppDirectory.equals(app.dataDir)) {
writableDirs.addAll(getWritableDirectoriesAndSubdirectoriesOf(new File(app.dataDir)));
}
}
@@ -624,7 +624,6 @@
"/mnt_ext/badablk3",
"/mnt_ext/cache",
"/mnt_ext/data",
- "/system/etc/dhcpcd/dhcpcd-run-hooks",
"/system/etc/security/drm",
"/synthesis/hades",
"/synthesis/chimaira",
diff --git a/tests/tests/print/AndroidTest.xml b/tests/tests/print/AndroidTest.xml
index 21d8f03..68aa157 100644
--- a/tests/tests/print/AndroidTest.xml
+++ b/tests/tests/print/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.print.cts" />
+ <option name="runtime-hint" value="12m35s" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index b92a924..59fb9f6 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -32,7 +32,8 @@
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil ctstestrunner platform-test-annotations
LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativehelper_compat_libc++
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index b4836d0..e56ac1d 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -23,7 +23,6 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
diff --git a/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java b/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
new file mode 100644
index 0000000..fc0333c
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.provider.cts;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+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.
+ */
+// To run the tests in this file w/o running all the cts tests:
+// make cts
+// cts-tradefed
+// run cts -m CtsProviderTestCases --test android.provider.cts.BlockedNumberBackupRestoreTest
+public class BlockedNumberBackupRestoreTest extends TestCaseThatRunsIfTelephonyIsEnabled {
+ private static final String TAG = "BlockedNumberBackupRestoreTest";
+ private static final String LOCAL_BACKUP_COMPONENT =
+ "android/com.android.internal.backup.LocalTransport";
+ private static final String BLOCKED_NUMBERS_PROVIDER_PACKAGE =
+ "com.android.providers.blockednumber";
+ private static final int BACKUP_TIMEOUT_MILLIS = 4000;
+ private static final Pattern BMGR_ENABLED_PATTERN = Pattern.compile(
+ "^Backup Manager currently (enabled|disabled)$");
+
+ private ContentResolver mContentResolver;
+ private Context mContext;
+ private String mOldTransport;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mContext = getInstrumentation().getContext();
+ mContentResolver = mContext.getContentResolver();
+
+ BlockedNumberTestUtils.setDefaultSmsApp(
+ true, mContext.getPackageName(), getInstrumentation().getUiAutomation());
+
+ mOldTransport = setBackupTransport(LOCAL_BACKUP_COMPONENT);
+ clearBlockedNumbers();
+ wipeBackup();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ wipeBackup();
+ clearBlockedNumbers();
+ setBackupTransport(mOldTransport);
+
+ BlockedNumberTestUtils.setDefaultSmsApp(
+ false, mContext.getPackageName(), getInstrumentation().getUiAutomation());
+
+ super.tearDown();
+ }
+
+ public void testBackupAndRestoreForSingleNumber() throws Exception {
+ if (!hasBackupTransport(LOCAL_BACKUP_COMPONENT)) {
+ Log.i(TAG, "skipping BlockedNumberBackupRestoreTest");
+ }
+
+ Log.i(TAG, "Adding blocked numbers.");
+ insertBlockedNumber("123456789");
+
+ Log.i(TAG, "Running backup.");
+ runBackup();
+ Thread.sleep(BACKUP_TIMEOUT_MILLIS);
+
+ Log.i(TAG, "Clearing blocked numbers.");
+ clearBlockedNumbers();
+ verifyBlockedNumbers();
+
+ Log.i(TAG, "Restoring blocked numbers.");
+ runRestore();
+ Thread.sleep(BACKUP_TIMEOUT_MILLIS);
+ verifyBlockedNumbers("123456789");
+ }
+
+ public void testBackupAndRestoreWithDeletion() throws Exception {
+ if (!hasBackupTransport(LOCAL_BACKUP_COMPONENT)) {
+ Log.i(TAG, "skipping BlockedNumberBackupRestoreTest");
+ }
+
+ Log.i(TAG, "Adding blocked numbers.");
+ insertBlockedNumber("123456789");
+ insertBlockedNumber("223456789");
+ insertBlockedNumber("323456789");
+
+ Log.i(TAG, "Running backup.");
+ runBackup();
+ Thread.sleep(BACKUP_TIMEOUT_MILLIS);
+
+ Log.i(TAG, "Deleting blocked number.");
+ deleteNumber("123456789");
+ verifyBlockedNumbers("223456789", "323456789");
+
+ Log.i(TAG, "Running backup.");
+ runBackup();
+ Thread.sleep(BACKUP_TIMEOUT_MILLIS);
+
+ Log.i(TAG, "Clearing blocked numbers.");
+ clearBlockedNumbers();
+ verifyBlockedNumbers();
+
+ Log.i(TAG, "Restoring blocked numbers.");
+ runRestore();
+ Thread.sleep(BACKUP_TIMEOUT_MILLIS);
+ verifyBlockedNumbers("223456789", "323456789");
+ }
+
+ private void insertBlockedNumber(String number) {
+ ContentValues cv = new ContentValues();
+ cv.put(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number);
+ mContentResolver.insert(BlockedNumberContract.BlockedNumbers.CONTENT_URI, cv);
+ }
+
+ private void deleteNumber(String number) {
+ assertEquals(1,
+ mContentResolver.delete(
+ BlockedNumberContract.BlockedNumbers.CONTENT_URI,
+ BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + "= ?",
+ new String[] {number}));
+ }
+
+ private void verifyBlockedNumbers(String ... blockedNumbers) {
+ assertEquals(blockedNumbers.length,
+ mContentResolver.query(
+ BlockedNumberContract.BlockedNumbers.CONTENT_URI, null, null, null, null)
+ .getCount());
+ for (String blockedNumber : blockedNumbers) {
+ assertTrue(BlockedNumberContract.isBlocked(mContext, blockedNumber));
+ }
+ }
+
+ private void clearBlockedNumbers() {
+ mContentResolver.delete(BlockedNumberContract.BlockedNumbers.CONTENT_URI, null, null);
+ }
+
+ private boolean hasBackupTransport(String transport) throws Exception {
+ String output = BlockedNumberTestUtils.executeShellCommand(
+ getInstrumentation().getUiAutomation(), "bmgr list transports");
+ for (String t : output.split(" ")) {
+ if ("*".equals(t)) {
+ // skip the current selection marker.
+ continue;
+ } else if (Objects.equals(transport, t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String setBackupTransport(String transport) throws Exception {
+ String output = exec("bmgr transport " + transport);
+ Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
+ Matcher matcher = pattern.matcher(output);
+ if (matcher.find()) {
+ return matcher.group(1);
+ } else {
+ throw new Exception("non-parsable output setting bmgr transport: " + output);
+ }
+ }
+
+ private void runBackup() throws Exception {
+ exec("bmgr backupnow " + BLOCKED_NUMBERS_PROVIDER_PACKAGE);
+ }
+
+ private void runRestore() throws Exception {
+ exec("bmgr restore " + BLOCKED_NUMBERS_PROVIDER_PACKAGE);
+ }
+
+ private void wipeBackup() throws Exception {
+ exec("bmgr wipe " + LOCAL_BACKUP_COMPONENT + " " + BLOCKED_NUMBERS_PROVIDER_PACKAGE);
+ }
+
+ private String exec(String command) throws Exception {
+ return BlockedNumberTestUtils.executeShellCommand(
+ getInstrumentation().getUiAutomation(), command);
+ }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/BlockedNumberContractTest.java b/tests/tests/provider/src/android/provider/cts/BlockedNumberContractTest.java
index 7ea63f3..9509d00 100644
--- a/tests/tests/provider/src/android/provider/cts/BlockedNumberContractTest.java
+++ b/tests/tests/provider/src/android/provider/cts/BlockedNumberContractTest.java
@@ -43,7 +43,7 @@
// To run the tests in this file w/o running all the cts tests:
// make cts
// cts-tradefed
-// run cts -c android.provider.cts.BlockedNumberContractTest
+// run cts -m CtsProviderTestCases --test android.provider.cts.BlockedNumberContractTest
public class BlockedNumberContractTest extends TestCaseThatRunsIfTelephonyIsEnabled {
private ContentResolver mContentResolver;
private Context mContext;
@@ -105,11 +105,7 @@
} catch (SecurityException expected) {
}
- try {
- BlockedNumberContract.canCurrentUserBlockNumbers(mContext);
- fail("Should throw SecurityException");
- } catch (SecurityException expected) {
- }
+ assertTrue(BlockedNumberContract.canCurrentUserBlockNumbers(mContext));
}
public void testGetType() throws Exception {
@@ -344,17 +340,7 @@
}
private void setDefaultSmsApp(boolean setToSmsApp) throws Exception {
- StringBuilder command = new StringBuilder();
- command.append("appops set ");
- command.append(mContext.getPackageName());
- command.append(" WRITE_SMS ");
- command.append(setToSmsApp ? "allow" : "default");
-
- ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
- .executeShellCommand(command.toString());
-
- InputStream is = new FileInputStream(pfd.getFileDescriptor());
- final byte[] buffer = new byte[8192];
- while ((is.read(buffer)) != -1);
+ BlockedNumberTestUtils.setDefaultSmsApp(
+ setToSmsApp, mContext.getPackageName(), getInstrumentation().getUiAutomation());
}
}
diff --git a/tests/tests/provider/src/android/provider/cts/BlockedNumberTestUtils.java b/tests/tests/provider/src/android/provider/cts/BlockedNumberTestUtils.java
new file mode 100644
index 0000000..b520542
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/BlockedNumberTestUtils.java
@@ -0,0 +1,58 @@
+/*
+ * 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.provider.cts;
+
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utility methods for blocked number cts tests.
+ */
+public class BlockedNumberTestUtils {
+ static void setDefaultSmsApp(boolean setToSmsApp, String packageName, UiAutomation uiAutomation)
+ throws Exception {
+ String command = String.format(
+ "appops set %s WRITE_SMS %s", packageName, setToSmsApp ? "allow" : "default");
+ executeShellCommand(uiAutomation, command);
+ }
+
+ static String executeShellCommand(UiAutomation uiAutomation, String command)
+ throws IOException {
+ ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command.toString());
+ BufferedReader br = null;
+ try (InputStream in = new FileInputStream(pfd.getFileDescriptor());) {
+ br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ String str = null;
+ StringBuilder out = new StringBuilder();
+ while ((str = br.readLine()) != null) {
+ out.append(str);
+ }
+ return out.toString();
+ } finally {
+ if (br != null) {
+ br.close();
+ }
+ }
+ }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index 589b5cd..8bf2516 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -28,6 +28,7 @@
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
+import android.platform.test.annotations.Presubmit;
import android.provider.MediaStore.Images.Media;
import android.provider.MediaStore.Images.Thumbnails;
import android.test.InstrumentationTestCase;
@@ -178,6 +179,7 @@
assertEquals(src.getHeight(), result.getHeight());
}
+ @Presubmit
public void testGetContentUri() {
Cursor c = null;
assertNotNull(c = mContentResolver.query(Media.getContentUri("internal"), null, null, null,
diff --git a/tests/tests/provider/src/android/provider/cts/UserDictionary_WordsTest.java b/tests/tests/provider/src/android/provider/cts/UserDictionary_WordsTest.java
index e226fef..27c48d3 100644
--- a/tests/tests/provider/src/android/provider/cts/UserDictionary_WordsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/UserDictionary_WordsTest.java
@@ -26,6 +26,10 @@
import java.util.ArrayList;
import java.util.Locale;
+/**
+ * NOTE: user dictionary is now accessible only by the current spellchecker and keyboard, so this
+ * test make sure they are not accessible by apps.
+ */
public class UserDictionary_WordsTest extends AndroidTestCase {
private ContentResolver mContentResolver;
@@ -68,14 +72,8 @@
Cursor cursor = mContentResolver.query(UserDictionary.Words.CONTENT_URI, WORDS_PROJECTION,
UserDictionary.Words.WORD + "='" + word + "'", null, null);
- assertTrue(cursor.moveToFirst());
- mAddedBackup.add(Uri.withAppendedPath(UserDictionary.Words.CONTENT_URI,
- cursor.getString(ID_INDEX)));
+ assertFalse("cursor is not empty", cursor.moveToFirst());
- assertEquals(1, cursor.getCount());
- assertEquals(word, cursor.getString(WORD_INDEX));
- assertEquals(frequency, cursor.getInt(FREQUENCY_INDEX));
- assertNull(cursor.getString(LOCALE_INDEX));
cursor.close();
}
@@ -92,14 +90,8 @@
Cursor cursor = mContentResolver.query(UserDictionary.Words.CONTENT_URI, WORDS_PROJECTION,
UserDictionary.Words.WORD + "='" + word + "'", null, null);
- assertTrue(cursor.moveToFirst());
- mAddedBackup.add(Uri.withAppendedPath(UserDictionary.Words.CONTENT_URI,
- cursor.getString(ID_INDEX)));
+ assertFalse("cursor is not empty", cursor.moveToFirst());
- assertEquals(1, cursor.getCount());
- assertEquals(word, cursor.getString(WORD_INDEX));
- assertEquals(expectedFrequency, cursor.getInt(FREQUENCY_INDEX));
- assertEquals(locale.toString(), cursor.getString(LOCALE_INDEX));
cursor.close();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
index 1400d86..d094119 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
@@ -312,6 +312,14 @@
cbrt(in.max32()));
}
+ static private Target.Floaty cos(double d, Target t) {
+ Target.Floaty in = t.newFloaty(d);
+ return t.newFloaty(
+ Math.cos(in.mid()),
+ Math.cos(in.min()),
+ Math.cos(in.max()));
+ }
+
static private Target.Floaty cos(float f, Target t) {
Target.Floaty in = t.new32(f);
return t.new32(
@@ -336,6 +344,22 @@
cos(in.max32()));
}
+ // Computes the cross product of two double-precision 3D vectors.
+ static private void cross(double[] v1, double[] v2, Target.Floaty[] out, Target t) {
+ Target.Floaty a12 = t.multiply(t.newFloaty(v1[1]), t.newFloaty(v2[2]));
+ Target.Floaty a21 = t.multiply(t.newFloaty(v1[2]), t.newFloaty(v2[1]));
+ out[0] = t.subtract(a12, a21);
+ Target.Floaty a02 = t.multiply(t.newFloaty(v1[0]), t.newFloaty(v2[2]));
+ Target.Floaty a20 = t.multiply(t.newFloaty(v1[2]), t.newFloaty(v2[0]));
+ out[1] = t.subtract(a20, a02);
+ Target.Floaty a01 = t.multiply(t.newFloaty(v1[0]), t.newFloaty(v2[1]));
+ Target.Floaty a10 = t.multiply(t.newFloaty(v1[1]), t.newFloaty(v2[0]));
+ out[2] = t.subtract(a01, a10);
+ if (out.length == 4) {
+ out[3] = t.newFloaty(0.f);
+ }
+ }
+
// Computes the cross product of two 3D vectors.
static private void cross(float[] v1, float[] v2, Target.Floaty[] out, Target t) {
Target.Floaty a12 = t.multiply(t.new32(v1[1]), t.new32(v2[2]));
@@ -395,6 +419,14 @@
expm1(in.max32()));
}
+ static private Target.Floaty floor(double d, Target t) {
+ Target.Floaty in = t.newFloaty(d);
+ return t.newFloaty(
+ Math.floor(in.mid()),
+ Math.floor(in.min()),
+ Math.floor(in.max()));
+ }
+
static private Target.Floaty hypot(float x, float y, Target t) {
Target.Floaty inX = t.new32(x);
Target.Floaty inY = t.new32(y);
@@ -499,6 +531,11 @@
}
}
+ static private Target.Floaty rsqrt(double d, Target t) {
+ Target.Floaty in = t.newFloaty(d);
+ return t.divide(t.newFloaty(1.), t.sqrt(in));
+ }
+
static private Target.Floaty rsqrt(float f, Target t) {
Target.Floaty in = t.new32(f);
return t.divide(t.new32(1.f), t.sqrt(in));
@@ -1050,6 +1087,15 @@
args.out = t.new32(Math.copySign(args.inMagnitudeValue, args.inSignValue));
}
+ static public void computeCos(TestCos.ArgumentsHalfHalf args, Target t) {
+ t.setPrecision(4, 128);
+ Target.Floaty in = t.newFloaty(args.inVDouble);
+ args.out = t.newFloaty(
+ Math.cos(in.mid()),
+ Math.cos(in.min()),
+ Math.cos(in.max()));
+ }
+
static public void computeCos(TestCos.ArgumentsFloatFloat args, Target t) {
t.setPrecision(4, 128);
args.out = cos(args.inV, t);
@@ -1065,6 +1111,11 @@
args.out = cospi(args.inV, t);
}
+ static public void computeCross(TestCross.ArgumentsHalfNHalfNHalfN args, Target t) {
+ t.setPrecision(1, 4);
+ cross(args.inLeftVectorDouble, args.inRightVectorDouble, args.out, t);
+ }
+
static public void computeCross(TestCross.ArgumentsFloatNFloatNFloatN args, Target t) {
t.setPrecision(1, 4);
cross(args.inLeftVector, args.inRightVector, args.out, t);
@@ -1195,6 +1246,11 @@
Math.max(0.f, r.max32()));
}
+ static public void computeFloor(TestFloor.ArgumentsHalfHalf args, Target t) {
+ t.setPrecision(0, 0);
+ args.out = floor(args.inVDouble, t);
+ }
+
static public void computeFloor(TestFloor.ArgumentsFloatFloat args, Target t) {
t.setPrecision(0, 0);
Target.Floaty in = t.new32(args.inV);
@@ -1866,6 +1922,11 @@
round(in.max32()));
}
+ static public void computeRsqrt(TestRsqrt.ArgumentsHalfHalf args, Target t) {
+ t.setPrecision(2, 2);
+ args.out = rsqrt(args.inVDouble, t);
+ }
+
static public void computeRsqrt(TestRsqrt.ArgumentsFloatFloat args, Target t) {
t.setPrecision(2, 2);
args.out = rsqrt(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 384e41c..8ef08f3 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/RSBaseCompute.java
@@ -129,7 +129,7 @@
alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
} else if (dataType == Element.DataType.FLOAT_16) {
short[] inArray = new short[INPUTSIZE * width];
- short min = 1024; // 0x0400 in hex, 2^-14, i.e. float16 MIN_NORMAL
+ short min = RSUtils.FLOAT16_MIN_NORMAL;
short max = 19456; // 0x4c00 in hex, 16.0 in float16
RSUtils.genRandomFloat16s(seed, min, max, inArray, includeExtremes);
alloc.copyFrom(inArray);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/RSUtils.java b/tests/tests/renderscript/src/android/renderscript/cts/RSUtils.java
index e7524a6..a95687d 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/RSUtils.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/RSUtils.java
@@ -26,6 +26,11 @@
* This class supplies some utils for renderscript tests
*/
public class RSUtils {
+ public static final short FLOAT16_POSITIVE_INFINITY = (short) 0x7c00;
+ public static final short FLOAT16_NEGATIVE_INFINITY = (short) 0xfc00;
+ public static final short FLOAT16_MIN_NORMAL = (short) 0x0400; // 0.00006103516
+ public static final short FLOAT16_MAX_VALUE = (short) 0x7bff; // 65504
+
private static final double[] sInterestingDoubles = {
0.0,
1.0,
@@ -182,10 +187,10 @@
}
if (includeExtremes) {
array[r.nextInt(array.length)] = (short) 0x7c01; // NaN
- array[r.nextInt(array.length)] = (short) 0x7c00; // POSITIVE_INFINITY
- array[r.nextInt(array.length)] = (short) 0xfc00; // NEGATIVE_INFINITY
- array[r.nextInt(array.length)] = (short) 0x0400; // MIN_NORMAL, 0.00006103516
- array[r.nextInt(array.length)] = (short) 0x7bff; // MAX_VALUE, 65504
+ array[r.nextInt(array.length)] = FLOAT16_POSITIVE_INFINITY;
+ array[r.nextInt(array.length)] = FLOAT16_NEGATIVE_INFINITY;
+ array[r.nextInt(array.length)] = FLOAT16_MIN_NORMAL;
+ array[r.nextInt(array.length)] = FLOAT16_MAX_VALUE;
array[r.nextInt(array.length)] = (short) 0x8400; // -MIN_NORMAL, -0.00006103516
array[r.nextInt(array.length)] = (short) 0xfbff; // -MAX_VALUE, -65504
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ReduceTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ReduceTest.java
index e30f3d3..b3c495c 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ReduceTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ReduceTest.java
@@ -31,13 +31,45 @@
mScript = new ScriptC_reduce(mRS);
mScript.set_negInf(Float.NEGATIVE_INFINITY);
mScript.set_posInf(Float.POSITIVE_INFINITY);
+ mScript.invoke_setInfsHalf(RSUtils.FLOAT16_NEGATIVE_INFINITY, RSUtils.FLOAT16_POSITIVE_INFINITY);
}
///////////////////////////////////////////////////////////////////
- private void assertEquals(Int2 javaRslt, Int2 rsRslt) {
- assertEquals("x", javaRslt.x, rsRslt.x);
- assertEquals("y", javaRslt.y, rsRslt.y);
+ private void assertEquals(final float[] javaRslt, final float[] rsRslt) {
+ assertEquals("length", javaRslt.length, rsRslt.length);
+ for (int i = 0; i < javaRslt.length; ++i)
+ assertEquals(String.valueOf(i), javaRslt[i], rsRslt[i]);
+ }
+
+ private void assertEquals(final short[] javaRslt, final short[] rsRslt) {
+ assertEquals("length", javaRslt.length, rsRslt.length);
+ for (int i = 0; i < javaRslt.length; ++i)
+ assertEquals(String.valueOf(i), javaRslt[i], rsRslt[i]);
+ }
+
+ private void assertEquals(final Short2[] javaRslt, final Short2[] rsRslt) {
+ assertEquals("length", javaRslt.length, rsRslt.length);
+ for (int i = 0; i < javaRslt.length; ++i)
+ assertEquals(String.valueOf(i), javaRslt[i], rsRslt[i]);
+ }
+
+ private void assertEquals(final String msg, final Int2 javaRslt, final Int2 rsRslt) {
+ assertEquals(msg + "(x)", javaRslt.x, rsRslt.x);
+ assertEquals(msg + "(y)", javaRslt.y, rsRslt.y);
+ }
+
+ private void assertEquals(final Int2 javaRslt, final Int2 rsRslt) {
+ assertEquals("", javaRslt, rsRslt);
+ }
+
+ private void assertEquals(final String msg, final Short2 javaRslt, final Short2 rsRslt) {
+ assertEquals(msg + "(x)", javaRslt.x, rsRslt.x);
+ assertEquals(msg + "(y)", javaRslt.y, rsRslt.y);
+ }
+
+ private void assertEquals(final Short2 javaRslt, final Short2 rsRslt) {
+ assertEquals("", javaRslt, rsRslt);
}
// Create a zero-initialized Allocation.
@@ -91,6 +123,12 @@
return array;
}
+ private static short[] createInputArrayHalf(int len, int seed) {
+ short[] array = new short[len];
+ RSUtils.genRandomFloat16s(seed, RSUtils.FLOAT16_MIN_NORMAL, RSUtils.FLOAT16_MAX_VALUE, array, false);
+ return array;
+ }
+
private static float[] createInputArrayFloat(int len, int seed) {
Random rand = new Random(seed);
float[] array = new float[len];
@@ -117,7 +155,7 @@
///////////////////////////////////////////////////////////////////
- private int addint(int[] input) {
+ private int addint(final int[] input) {
int rslt = 0;
for (int idx = 0; idx < input.length; ++idx)
rslt += input[idx];
@@ -150,7 +188,7 @@
///////////////////////////////////////////////////////////////////
- private Int2 findMinAndMax(float[] input) {
+ private Int2 findMinAndMax(final float[] input) {
float minVal = Float.POSITIVE_INFINITY;
int minIdx = -1;
float maxVal = Float.NEGATIVE_INFINITY;
@@ -181,6 +219,129 @@
///////////////////////////////////////////////////////////////////
+ private Short2 findMinAndMaxHalf(final short[] inputArray) {
+ Allocation inputAllocation = Allocation.createSized(mRS, Element.F16(mRS), inputArray.length);
+ inputAllocation.copyFrom(inputArray);
+
+ Allocation outputAllocation = Allocation.createSized(mRS, Element.F16_2(mRS), 1);
+
+ mScript.invoke_findMinAndMaxHalf(outputAllocation, inputAllocation);
+
+ short[] outputArray = new short[2];
+ outputAllocation.copyTo(outputArray);
+ return new Short2(outputArray[0], outputArray[1]);
+ }
+
+ private short[] findMinAndMaxHalfIntoArray(final short[] inputArray) {
+ final Short2 vectorResult = findMinAndMaxHalf(inputArray);
+ final short[] arrayResult = new short[] { vectorResult.x, vectorResult.y };
+ return arrayResult;
+ }
+
+ public void testFindMinAndMaxHalf() {
+ // fewer members in the array than there are distinct half values
+ final short[] input = createInputArrayHalf(1000, 23);
+
+ // test Short2 result
+ final Short2 javaRslt = findMinAndMaxHalf(input);
+ final Short2 rsRslt = mScript.reduce_findMinAndMaxHalf(input).get();
+ assertEquals(javaRslt, rsRslt);
+
+ // test short[2] result
+ final short[] javaRsltIntoArray = findMinAndMaxHalfIntoArray(input);
+ final short[] rsRsltIntoArray = mScript.reduce_findMinAndMaxHalfIntoArray(input).get();
+ assertEquals(javaRsltIntoArray, rsRsltIntoArray);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ // The input is a flattened representation of an array of 2-vector
+ private Short2[] findMinAndMaxHalf2(final short[] inputArray) {
+ assertEquals(inputArray.length % 2, 0);
+
+ Allocation inputAllocation = Allocation.createSized(mRS, Element.F16_2(mRS), inputArray.length / 2);
+ inputAllocation.copyFrom(inputArray);
+
+ Allocation outputAllocation = Allocation.createSized(mRS, Element.F16_2(mRS), 2);
+
+ mScript.invoke_findMinAndMaxHalf2(outputAllocation, inputAllocation);
+
+ short[] outputArray = new short[4];
+ outputAllocation.copyTo(outputArray);
+ return new Short2[] { new Short2(outputArray[0], outputArray[1]),
+ new Short2(outputArray[2], outputArray[3]) };
+ }
+
+ public void testFindMinAndMaxHalf2() {
+ // fewer members in the array than there are distinct half values
+ final short[] input = createInputArrayHalf(1000, 25);
+
+ final Short2[] javaRslt = findMinAndMaxHalf2(input);
+ final Short2[] rsRslt = mScript.reduce_findMinAndMaxHalf2(input).get();
+
+ assertEquals(javaRslt, rsRslt);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ // Both the input and the result are linearized representations of 2x2 matrices.
+ private float[] findMinMat(final float[] inputArray) {
+ float[] result = new float[4];
+ for (int i = 0; i < 4; ++i)
+ result[i] = Float.POSITIVE_INFINITY;
+
+ for (int i = 0; i < inputArray.length; ++i)
+ result[i % 4] = Math.min(result[i % 4], inputArray[i]);
+
+ return result;
+ }
+
+ public void testFindMinMat() {
+ final int length = 100000;
+
+ final float[] inputArray = createInputArrayFloat(4 * length, 24);
+ Allocation inputAllocation = Allocation.createSized(mRS, Element.MATRIX_2X2(mRS), length);
+ inputAllocation.copyFromUnchecked(inputArray);
+
+ final float[] javaRslt = findMinMat(inputArray);
+ final float[] rsRslt = mScript.reduce_findMinMat(inputAllocation).get();
+
+ assertEquals(javaRslt, rsRslt);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
+ // Both the input and the result are linearized representations of 2x2 matrices.
+ private float[] findMinAndMaxMat(final float[] inputArray) {
+ float[] result = new float[8];
+ for (int i = 0; i < 4; ++i) {
+ result[i+0] = Float.POSITIVE_INFINITY;
+ result[i+4] = Float.NEGATIVE_INFINITY;
+ }
+
+ for (int i = 0; i < inputArray.length; ++i) {
+ result[0 + i % 4] = Math.min(result[0 + i % 4], inputArray[i]);
+ result[4 + i % 4] = Math.max(result[4 + i % 4], inputArray[i]);
+ }
+
+ return result;
+ }
+
+ public void testFindMinAndMaxMat() {
+ final int length = 100000;
+
+ final float[] inputArray = createInputArrayFloat(4 * length, 26);
+ Allocation inputAllocation = Allocation.createSized(mRS, Element.MATRIX_2X2(mRS), length);
+ inputAllocation.copyFromUnchecked(inputArray);
+
+ final float[] javaRslt = findMinAndMaxMat(inputArray);
+ final float[] rsRslt = mScript.reduce_findMinAndMaxMat(inputAllocation).get();
+
+ assertEquals(javaRslt, rsRslt);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+
public void testFz() {
final int inputLen = 100000;
int[] input = createInputArrayInt(inputLen, 5);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestConvert.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestConvert.java
index 464200d..319b104 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestConvert.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestConvert.java
@@ -10941,7 +10941,7 @@
}
private void checkConvertDouble2Long2() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 2, 0x430cbe95l, -4.2949662730000000000e+09, 4.2949662720000000000e+09);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 2, 0x430cbe95l, -9.2233720368547747840e+18, 9.2233720368547747840e+18);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.SIGNED_64, 2), INPUTSIZE);
script.forEach_testConvertLong2Double2Long2(inV, out);
@@ -11009,7 +11009,7 @@
}
private void checkConvertDouble3Long3() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 3, 0xa2148389l, -4.2949662730000000000e+09, 4.2949662720000000000e+09);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 3, 0xa2148389l, -9.2233720368547747840e+18, 9.2233720368547747840e+18);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.SIGNED_64, 3), INPUTSIZE);
script.forEach_testConvertLong3Double3Long3(inV, out);
@@ -11077,7 +11077,7 @@
}
private void checkConvertDouble4Long4() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 4, 0x11c487dl, -4.2949662730000000000e+09, 4.2949662720000000000e+09);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 4, 0x11c487dl, -9.2233720368547747840e+18, 9.2233720368547747840e+18);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.SIGNED_64, 4), INPUTSIZE);
script.forEach_testConvertLong4Double4Long4(inV, out);
@@ -11568,7 +11568,7 @@
}
private void checkConvertDouble2Ulong2() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 2, 0x7e12ff5el, 0.0000000000000000000e+00, 4.2949652480000000000e+09);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 2, 0x7e12ff5el, 0.0000000000000000000e+00, 1.8446744073709549568e+19);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.UNSIGNED_64, 2), INPUTSIZE);
script.forEach_testConvertUlong2Double2Ulong2(inV, out);
@@ -11636,7 +11636,7 @@
}
private void checkConvertDouble3Ulong3() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 3, 0x742e203cl, 0.0000000000000000000e+00, 4.2949652480000000000e+09);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 3, 0x742e203cl, 0.0000000000000000000e+00, 1.8446744073709549568e+19);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.UNSIGNED_64, 3), INPUTSIZE);
script.forEach_testConvertUlong3Double3Ulong3(inV, out);
@@ -11704,7 +11704,7 @@
}
private void checkConvertDouble4Ulong4() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 4, 0x6a49411al, 0.0000000000000000000e+00, 4.2949652480000000000e+09);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_64, 4, 0x6a49411al, 0.0000000000000000000e+00, 1.8446744073709549568e+19);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.UNSIGNED_64, 4), INPUTSIZE);
script.forEach_testConvertUlong4Double4Ulong4(inV, out);
@@ -18077,7 +18077,7 @@
}
private void checkConvertFloat2Long2() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 2, 0x7d7c0ae0l, -1.0000000000000000000e+00, 0.0000000000000000000e+00);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 2, 0x7d7c0ae0l, -9.2233714870989619200e+18, 9.2233714870989619200e+18);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.SIGNED_64, 2), INPUTSIZE);
script.forEach_testConvertLong2Float2Long2(inV, out);
@@ -18145,7 +18145,7 @@
}
private void checkConvertFloat3Long3() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 3, 0xdc83cfd4l, -1.0000000000000000000e+00, 0.0000000000000000000e+00);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 3, 0xdc83cfd4l, -9.2233714870989619200e+18, 9.2233714870989619200e+18);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.SIGNED_64, 3), INPUTSIZE);
script.forEach_testConvertLong3Float3Long3(inV, out);
@@ -18213,7 +18213,7 @@
}
private void checkConvertFloat4Long4() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 4, 0x3b8b94c8l, -1.0000000000000000000e+00, 0.0000000000000000000e+00);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 4, 0x3b8b94c8l, -9.2233714870989619200e+18, 9.2233714870989619200e+18);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.SIGNED_64, 4), INPUTSIZE);
script.forEach_testConvertLong4Float4Long4(inV, out);
@@ -19540,7 +19540,7 @@
}
private void checkConvertFloat2Ulong2() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 2, 0x4ec4cff7l, 0.0000000000000000000e+00, 0.0000000000000000000e+00);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 2, 0x4ec4cff7l, 0.0000000000000000000e+00, 1.8446742974197923840e+19);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.UNSIGNED_64, 2), INPUTSIZE);
script.forEach_testConvertUlong2Float2Ulong2(inV, out);
@@ -19608,7 +19608,7 @@
}
private void checkConvertFloat3Ulong3() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 3, 0x44dff0d5l, 0.0000000000000000000e+00, 0.0000000000000000000e+00);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 3, 0x44dff0d5l, 0.0000000000000000000e+00, 1.8446742974197923840e+19);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.UNSIGNED_64, 3), INPUTSIZE);
script.forEach_testConvertUlong3Float3Ulong3(inV, out);
@@ -19676,7 +19676,7 @@
}
private void checkConvertFloat4Ulong4() {
- Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 4, 0x3afb11b3l, 0.0000000000000000000e+00, 0.0000000000000000000e+00);
+ Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_32, 4, 0x3afb11b3l, 0.0000000000000000000e+00, 1.8446742974197923840e+19);
try {
Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.UNSIGNED_64, 4), INPUTSIZE);
script.forEach_testConvertUlong4Float4Ulong4(inV, out);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.java
index 4b7751b..9d9b0e5 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.java
@@ -318,10 +318,312 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalf {
+ public short inV;
+ public double inVDouble;
+ public Target.Floaty out;
+ }
+
+ private void checkCosHalfHalf() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x151d6890l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.forEach_testCosHalfHalf(inV, out);
+ verifyResultsCosHalfHalf(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.forEach_testCosHalfHalf(inV, out);
+ verifyResultsCosHalfHalf(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsCosHalfHalf(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeCos(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkCosHalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkCosHalf2Half2() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x289f4632l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.forEach_testCosHalf2Half2(inV, out);
+ verifyResultsCosHalf2Half2(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalf2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.forEach_testCosHalf2Half2(inV, out);
+ verifyResultsCosHalf2Half2(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalf2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsCosHalf2Half2(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeCos(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkCosHalf2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkCosHalf3Half3() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x87a70b26l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.forEach_testCosHalf3Half3(inV, out);
+ verifyResultsCosHalf3Half3(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalf3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.forEach_testCosHalf3Half3(inV, out);
+ verifyResultsCosHalf3Half3(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalf3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsCosHalf3Half3(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeCos(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkCosHalf3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkCosHalf4Half4() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xe6aed01al, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.forEach_testCosHalf4Half4(inV, out);
+ verifyResultsCosHalf4Half4(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalf4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.forEach_testCosHalf4Half4(inV, out);
+ verifyResultsCosHalf4Half4(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCosHalf4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsCosHalf4Half4(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeCos(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkCosHalf4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testCos() {
checkCosFloatFloat();
checkCosFloat2Float2();
checkCosFloat3Float3();
checkCosFloat4Float4();
+ checkCosHalfHalf();
+ checkCosHalf2Half2();
+ checkCosHalf3Half3();
+ checkCosHalf4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.rs
index 67f3d14..f7268cc 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCos.rs
@@ -35,3 +35,19 @@
float4 __attribute__((kernel)) testCosFloat4Float4(float4 inV) {
return cos(inV);
}
+
+half __attribute__((kernel)) testCosHalfHalf(half inV) {
+ return cos(inV);
+}
+
+half2 __attribute__((kernel)) testCosHalf2Half2(half2 inV) {
+ return cos(inV);
+}
+
+half3 __attribute__((kernel)) testCosHalf3Half3(half3 inV) {
+ return cos(inV);
+}
+
+half4 __attribute__((kernel)) testCosHalf4Half4(half4 inV) {
+ return cos(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.java
index 31927b1..57b4a07 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.java
@@ -225,8 +225,214 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfNHalfNHalfN {
+ public short[] inLeftVector;
+ public double[] inLeftVectorDouble;
+ public short[] inRightVector;
+ public double[] inRightVectorDouble;
+ public Target.Floaty[] out;
+ }
+
+ private void checkCrossHalf3Half3Half3() {
+ Allocation inLeftVector = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0xfc3afdafl, false);
+ Allocation inRightVector = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0xcc0165eal, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.set_gAllocInRightVector(inRightVector);
+ script.forEach_testCrossHalf3Half3Half3(inLeftVector, out);
+ verifyResultsCrossHalf3Half3Half3(inLeftVector, inRightVector, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCrossHalf3Half3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.set_gAllocInRightVector(inRightVector);
+ scriptRelaxed.forEach_testCrossHalf3Half3Half3(inLeftVector, out);
+ verifyResultsCrossHalf3Half3Half3(inLeftVector, inRightVector, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCrossHalf3Half3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsCrossHalf3Half3Half3(Allocation inLeftVector, Allocation inRightVector, Allocation out, boolean relaxed) {
+ short[] arrayInLeftVector = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInLeftVector, (short) 42);
+ inLeftVector.copyTo(arrayInLeftVector);
+ short[] arrayInRightVector = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInRightVector, (short) 42);
+ inRightVector.copyTo(arrayInRightVector);
+ 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++) {
+ ArgumentsHalfNHalfNHalfN args = new ArgumentsHalfNHalfNHalfN();
+ // Create the appropriate sized arrays in args
+ args.inLeftVector = new short[3];
+ args.inLeftVectorDouble = new double[3];
+ args.inRightVector = new short[3];
+ args.inRightVectorDouble = new double[3];
+ args.out = new Target.Floaty[3];
+ // Fill args with the input values
+ for (int j = 0; j < 3 ; j++) {
+ args.inLeftVector[j] = arrayInLeftVector[i * 4 + j];
+ args.inLeftVectorDouble[j] = Float16Utils.convertFloat16ToDouble(args.inLeftVector[j]);
+ }
+ for (int j = 0; j < 3 ; j++) {
+ args.inRightVector[j] = arrayInRightVector[i * 4 + j];
+ args.inRightVectorDouble[j] = Float16Utils.convertFloat16ToDouble(args.inRightVector[j]);
+ }
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeCross(args, target);
+
+ // Compare the expected outputs to the actual values returned by RS.
+ boolean valid = true;
+ for (int j = 0; j < 3 ; j++) {
+ if (!args.out[j].couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ for (int j = 0; j < 3 ; j++) {
+ message.append("Input inLeftVector: ");
+ appendVariableToMessage(message, arrayInLeftVector[i * 4 + j]);
+ message.append("\n");
+ }
+ for (int j = 0; j < 3 ; j++) {
+ message.append("Input inRightVector: ");
+ appendVariableToMessage(message, arrayInRightVector[i * 4 + j]);
+ message.append("\n");
+ }
+ for (int j = 0; j < 3 ; j++) {
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out[j]);
+ 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[j].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("]");
+ }
+ }
+ assertFalse("Incorrect output for checkCrossHalf3Half3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkCrossHalf4Half4Half4() {
+ Allocation inLeftVector = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xa8692054l, false);
+ Allocation inRightVector = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xb7c137a1l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.set_gAllocInRightVector(inRightVector);
+ script.forEach_testCrossHalf4Half4Half4(inLeftVector, out);
+ verifyResultsCrossHalf4Half4Half4(inLeftVector, inRightVector, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCrossHalf4Half4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.set_gAllocInRightVector(inRightVector);
+ scriptRelaxed.forEach_testCrossHalf4Half4Half4(inLeftVector, out);
+ verifyResultsCrossHalf4Half4Half4(inLeftVector, inRightVector, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testCrossHalf4Half4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsCrossHalf4Half4Half4(Allocation inLeftVector, Allocation inRightVector, Allocation out, boolean relaxed) {
+ short[] arrayInLeftVector = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInLeftVector, (short) 42);
+ inLeftVector.copyTo(arrayInLeftVector);
+ short[] arrayInRightVector = new short[INPUTSIZE * 4];
+ Arrays.fill(arrayInRightVector, (short) 42);
+ inRightVector.copyTo(arrayInRightVector);
+ 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++) {
+ ArgumentsHalfNHalfNHalfN args = new ArgumentsHalfNHalfNHalfN();
+ // Create the appropriate sized arrays in args
+ args.inLeftVector = new short[4];
+ args.inLeftVectorDouble = new double[4];
+ args.inRightVector = new short[4];
+ args.inRightVectorDouble = new double[4];
+ args.out = new Target.Floaty[4];
+ // Fill args with the input values
+ for (int j = 0; j < 4 ; j++) {
+ args.inLeftVector[j] = arrayInLeftVector[i * 4 + j];
+ args.inLeftVectorDouble[j] = Float16Utils.convertFloat16ToDouble(args.inLeftVector[j]);
+ }
+ for (int j = 0; j < 4 ; j++) {
+ args.inRightVector[j] = arrayInRightVector[i * 4 + j];
+ args.inRightVectorDouble[j] = Float16Utils.convertFloat16ToDouble(args.inRightVector[j]);
+ }
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeCross(args, target);
+
+ // Compare the expected outputs to the actual values returned by RS.
+ boolean valid = true;
+ for (int j = 0; j < 4 ; j++) {
+ if (!args.out[j].couldBe(Float16Utils.convertFloat16ToDouble(arrayOut[i * 4 + j]))) {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ if (!errorFound) {
+ errorFound = true;
+ for (int j = 0; j < 4 ; j++) {
+ message.append("Input inLeftVector: ");
+ appendVariableToMessage(message, arrayInLeftVector[i * 4 + j]);
+ message.append("\n");
+ }
+ for (int j = 0; j < 4 ; j++) {
+ message.append("Input inRightVector: ");
+ appendVariableToMessage(message, arrayInRightVector[i * 4 + j]);
+ message.append("\n");
+ }
+ for (int j = 0; j < 4 ; j++) {
+ message.append("Expected output out: ");
+ appendVariableToMessage(message, args.out[j]);
+ 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[j].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("]");
+ }
+ }
+ assertFalse("Incorrect output for checkCrossHalf4Half4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testCross() {
checkCrossFloat3Float3Float3();
checkCrossFloat4Float4Float4();
+ checkCrossHalf3Half3Half3();
+ checkCrossHalf4Half4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.rs
index e87e0fb..9849707f 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestCross.rs
@@ -30,3 +30,13 @@
float4 inRightVector = rsGetElementAt_float4(gAllocInRightVector, x);
return cross(inLeftVector, inRightVector);
}
+
+half3 __attribute__((kernel)) testCrossHalf3Half3Half3(half3 inLeftVector, unsigned int x) {
+ half3 inRightVector = rsGetElementAt_half3(gAllocInRightVector, x);
+ return cross(inLeftVector, inRightVector);
+}
+
+half4 __attribute__((kernel)) testCrossHalf4Half4Half4(half4 inLeftVector, unsigned int x) {
+ half4 inRightVector = rsGetElementAt_half4(gAllocInRightVector, x);
+ return cross(inLeftVector, inRightVector);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.java
index 96c70b9..35238b3 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.java
@@ -318,10 +318,312 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalf {
+ public short inV;
+ public double inVDouble;
+ public Target.Floaty out;
+ }
+
+ private void checkFloorHalfHalf() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x56dc16ffl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.forEach_testFloorHalfHalf(inV, out);
+ verifyResultsFloorHalfHalf(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.forEach_testFloorHalfHalf(inV, out);
+ verifyResultsFloorHalfHalf(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsFloorHalfHalf(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeFloor(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkFloorHalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkFloorHalf2Half2() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x2d925e9l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.forEach_testFloorHalf2Half2(inV, out);
+ verifyResultsFloorHalf2Half2(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalf2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.forEach_testFloorHalf2Half2(inV, out);
+ verifyResultsFloorHalf2Half2(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalf2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsFloorHalf2Half2(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeFloor(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkFloorHalf2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkFloorHalf3Half3() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x61e0eaddl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.forEach_testFloorHalf3Half3(inV, out);
+ verifyResultsFloorHalf3Half3(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalf3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.forEach_testFloorHalf3Half3(inV, out);
+ verifyResultsFloorHalf3Half3(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalf3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsFloorHalf3Half3(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeFloor(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkFloorHalf3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkFloorHalf4Half4() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xc0e8afd1l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.forEach_testFloorHalf4Half4(inV, out);
+ verifyResultsFloorHalf4Half4(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalf4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.forEach_testFloorHalf4Half4(inV, out);
+ verifyResultsFloorHalf4Half4(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testFloorHalf4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsFloorHalf4Half4(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeFloor(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkFloorHalf4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testFloor() {
checkFloorFloatFloat();
checkFloorFloat2Float2();
checkFloorFloat3Float3();
checkFloorFloat4Float4();
+ checkFloorHalfHalf();
+ checkFloorHalf2Half2();
+ checkFloorHalf3Half3();
+ checkFloorHalf4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.rs
index c0c3036..def706d 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestFloor.rs
@@ -35,3 +35,19 @@
float4 __attribute__((kernel)) testFloorFloat4Float4(float4 inV) {
return floor(inV);
}
+
+half __attribute__((kernel)) testFloorHalfHalf(half inV) {
+ return floor(inV);
+}
+
+half2 __attribute__((kernel)) testFloorHalf2Half2(half2 inV) {
+ return floor(inV);
+}
+
+half3 __attribute__((kernel)) testFloorHalf3Half3(half3 inV) {
+ return floor(inV);
+}
+
+half4 __attribute__((kernel)) testFloorHalf4Half4(half4 inV) {
+ return floor(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.java
index f91495c..118df96 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.java
@@ -318,10 +318,312 @@
(relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
}
+ public class ArgumentsHalfHalf {
+ public short inV;
+ public double inVDouble;
+ public Target.Floaty out;
+ }
+
+ private void checkRsqrtHalfHalf() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x8234e8f1l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ script.forEach_testRsqrtHalfHalf(inV, out);
+ verifyResultsRsqrtHalfHalf(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalfHalf: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+ scriptRelaxed.forEach_testRsqrtHalfHalf(inV, out);
+ verifyResultsRsqrtHalfHalf(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalfHalf: " + e.toString());
+ }
+ }
+
+ private void verifyResultsRsqrtHalfHalf(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeRsqrt(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkRsqrtHalfHalf" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkRsqrtHalf2Half2() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x175d82cbl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ script.forEach_testRsqrtHalf2Half2(inV, out);
+ verifyResultsRsqrtHalf2Half2(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalf2Half2: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+ scriptRelaxed.forEach_testRsqrtHalf2Half2(inV, out);
+ verifyResultsRsqrtHalf2Half2(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalf2Half2: " + e.toString());
+ }
+ }
+
+ private void verifyResultsRsqrtHalf2Half2(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeRsqrt(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkRsqrtHalf2Half2" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkRsqrtHalf3Half3() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x766547bfl, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ script.forEach_testRsqrtHalf3Half3(inV, out);
+ verifyResultsRsqrtHalf3Half3(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalf3Half3: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+ scriptRelaxed.forEach_testRsqrtHalf3Half3(inV, out);
+ verifyResultsRsqrtHalf3Half3(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalf3Half3: " + e.toString());
+ }
+ }
+
+ private void verifyResultsRsqrtHalf3Half3(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeRsqrt(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkRsqrtHalf3Half3" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
+ private void checkRsqrtHalf4Half4() {
+ Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xd56d0cb3l, false);
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ script.forEach_testRsqrtHalf4Half4(inV, out);
+ verifyResultsRsqrtHalf4Half4(inV, out, false);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalf4Half4: " + e.toString());
+ }
+ try {
+ Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+ scriptRelaxed.forEach_testRsqrtHalf4Half4(inV, out);
+ verifyResultsRsqrtHalf4Half4(inV, out, true);
+ } catch (Exception e) {
+ throw new RSRuntimeException("RenderScript. Can't invoke forEach_testRsqrtHalf4Half4: " + e.toString());
+ }
+ }
+
+ private void verifyResultsRsqrtHalf4Half4(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);
+ // Figure out what the outputs should have been.
+ Target target = new Target(Target.FunctionType.NORMAL, Target.ReturnType.HALF, relaxed);
+ CoreMathVerifier.computeRsqrt(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 inV: ");
+ appendVariableToMessage(message, args.inV);
+ 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 checkRsqrtHalf4Half4" +
+ (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+ }
+
public void testRsqrt() {
checkRsqrtFloatFloat();
checkRsqrtFloat2Float2();
checkRsqrtFloat3Float3();
checkRsqrtFloat4Float4();
+ checkRsqrtHalfHalf();
+ checkRsqrtHalf2Half2();
+ checkRsqrtHalf3Half3();
+ checkRsqrtHalf4Half4();
}
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.rs
index 579b7af..03ef4a1 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestRsqrt.rs
@@ -35,3 +35,19 @@
float4 __attribute__((kernel)) testRsqrtFloat4Float4(float4 inV) {
return rsqrt(inV);
}
+
+half __attribute__((kernel)) testRsqrtHalfHalf(half inV) {
+ return rsqrt(inV);
+}
+
+half2 __attribute__((kernel)) testRsqrtHalf2Half2(half2 inV) {
+ return rsqrt(inV);
+}
+
+half3 __attribute__((kernel)) testRsqrtHalf3Half3(half3 inV) {
+ return rsqrt(inV);
+}
+
+half4 __attribute__((kernel)) testRsqrtHalf4Half4(half4 inV) {
+ return rsqrt(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
index ab2268e..6d7870d 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
@@ -18,6 +18,19 @@
float negInf, posInf;
+static half negInfHalf, posInfHalf;
+
+// At present, no support for global of type half, or for invokable
+// taking an argument of type half.
+static void translate(half *tgt, const short src) {
+ for (int i = 0; i < sizeof(half); ++i)
+ ((char *)tgt)[i] = ((const char *)&src)[i];
+}
+void setInfsHalf(short forNegInfHalf, short forPosInfHalf) {
+ translate(&negInfHalf, forNegInfHalf);
+ translate(&posInfHalf, forPosInfHalf);
+}
+
/////////////////////////////////////////////////////////////////////////
#pragma rs reduce(addint) \
@@ -27,17 +40,7 @@
/////////////////////////////////////////////////////////////////////////
-#pragma rs reduce(dp) \
- accumulator(dpAccum) combiner(dpSum)
-
-static void dpAccum(float *accum, float in1, float in2) {
- *accum += in1*in2;
-}
-
-// combiner function
-static void dpSum(float *accum, const float *val) { *accum += *val; }
-
-/////////////////////////////////////////////////////////////////////////
+// Finds LOCATION of min and max float values
#pragma rs reduce(findMinAndMax) \
initializer(fMMInit) accumulator(fMMAccumulator) \
@@ -84,6 +87,225 @@
/////////////////////////////////////////////////////////////////////////
+// finds min and max half values (not their locations)
+
+// tests half input and half2 result
+
+// .. reduction form
+
+#pragma rs reduce(findMinAndMaxHalf) \
+ initializer(fMMHalfInit) accumulator(fMMHalfAccumulator) \
+ combiner(fMMHalfCombiner) outconverter(fMMHalfOutConverter)
+
+typedef struct {
+ half min, max;
+} MinAndMaxHalf;
+
+static void fMMHalfInit(MinAndMaxHalf *accum) {
+ accum->min = posInfHalf;
+ accum->max = negInfHalf;
+}
+
+static void fMMHalfAccumulator(MinAndMaxHalf *accum, half in) {
+ accum->min = fmin(accum->min, in);
+ accum->max = fmax(accum->max, in);
+}
+
+static void fMMHalfCombiner(MinAndMaxHalf *accum,
+ const MinAndMaxHalf *val) {
+ fMMHalfAccumulator(accum, val->min);
+ fMMHalfAccumulator(accum, val->max);
+}
+
+static void fMMHalfOutConverter(half2 *result,
+ const MinAndMaxHalf *val) {
+ result->x = val->min;
+ result->y = val->max;
+}
+
+// .. invokable (non reduction) form (no support for half computations in Java)
+
+void findMinAndMaxHalf(rs_allocation out, rs_allocation in) {
+ half min = posInfHalf, max = negInfHalf;
+
+ const uint32_t len = rsAllocationGetDimX(in);
+ for (uint32_t idx = 0; idx < len; ++idx) {
+ const half val = rsGetElementAt_half(in, idx);
+ min = fmin(min, val);
+ max = fmax(max, val);
+ }
+
+ half2 result;
+ result.x = min;
+ result.y = max;
+ rsSetElementAt_half2(out, result, 0);
+}
+
+// tests half input and array of half result;
+// reuses functions of findMinAndMaxHalf reduction kernel
+
+#pragma rs reduce(findMinAndMaxHalfIntoArray) \
+ initializer(fMMHalfInit) accumulator(fMMHalfAccumulator) \
+ combiner(fMMHalfCombiner) outconverter(fMMHalfOutConverterIntoArray)
+
+static void fMMHalfOutConverterIntoArray(half (*result)[2],
+ const MinAndMaxHalf *val) {
+ (*result)[0] = val->min;
+ (*result)[1] = val->max;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+// finds min and max half2 values (not their locations), element-wise:
+// result[0].x = fmin(input[...].x)
+// result[0].y = fmin(input[...].y)
+// result[1].x = fmax(input[...].x)
+// result[1].y = fmax(input[...].y)
+
+// tests half2 input and half2[] result
+
+// .. reduction form
+
+#pragma rs reduce(findMinAndMaxHalf2) \
+ initializer(fMMHalf2Init) accumulator(fMMHalf2Accumulator) \
+ combiner(fMMHalf2Combiner) outconverter(fMMHalf2OutConverter)
+
+typedef struct {
+ half2 min, max;
+} MinAndMaxHalf2;
+
+static void fMMHalf2Init(MinAndMaxHalf2 *accum) {
+ accum->min.x = posInfHalf;
+ accum->min.y = posInfHalf;
+ accum->max.x = negInfHalf;
+ accum->max.y = negInfHalf;
+}
+
+static void fMMHalf2Accumulator(MinAndMaxHalf2 *accum, half2 in) {
+ accum->min.x = fmin(accum->min.x, in.x);
+ accum->min.y = fmin(accum->min.y, in.y);
+ accum->max.x = fmax(accum->max.x, in.x);
+ accum->max.y = fmax(accum->max.y, in.y);
+}
+
+static void fMMHalf2Combiner(MinAndMaxHalf2 *accum,
+ const MinAndMaxHalf2 *val) {
+ fMMHalf2Accumulator(accum, val->min);
+ fMMHalf2Accumulator(accum, val->max);
+}
+
+typedef half2 ArrayOf2Half2[2];
+
+static void fMMHalf2OutConverter(ArrayOf2Half2 *result,
+ const MinAndMaxHalf2 *val) {
+ (*result)[0] = val->min;
+ (*result)[1] = val->max;
+}
+
+// .. invokable (non reduction) form (no support for half computations in Java)
+
+void findMinAndMaxHalf2(rs_allocation out, rs_allocation in) {
+ half2 min = { posInfHalf, posInfHalf }, max = { negInfHalf, negInfHalf };
+
+ const uint32_t len = rsAllocationGetDimX(in);
+ for (uint32_t idx = 0; idx < len; ++idx) {
+ const half2 val = rsGetElementAt_half2(in, idx);
+ min.x = fmin(min.x, val.x);
+ min.y = fmin(min.y, val.y);
+ max.x = fmax(max.x, val.x);
+ max.y = fmax(max.y, val.y);
+ }
+
+ rsSetElementAt_half2(out, min, 0);
+ rsSetElementAt_half2(out, max, 1);
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+// finds min values (not their locations) from matrix input
+
+// tests matrix input and matrix accumulator
+
+#pragma rs reduce(findMinMat) \
+ initializer(fMinMatInit) accumulator(fMinMatAccumulator) \
+ outconverter(fMinMatOutConverter)
+
+static void fMinMatInit(rs_matrix2x2 *accum) {
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ rsMatrixSet(accum, i, j, posInf);
+}
+
+static void fMinMatAccumulator(rs_matrix2x2 *accum, rs_matrix2x2 val) {
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ const float accumElt = rsMatrixGet(accum, i, j);
+ const float valElt = rsMatrixGet(&val, i, j);
+ if (valElt < accumElt)
+ rsMatrixSet(accum, i, j, valElt);
+ }
+ }
+}
+
+// reduction does not support matrix result, so use array instead
+static void fMinMatOutConverter(float (*result)[4], const rs_matrix2x2 *accum) {
+ for (int i = 0; i < 4; ++i)
+ (*result)[i] = accum->m[i];
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+// finds min and max values (not their locations) from matrix input
+
+// tests matrix input and array of matrix accumulator (0 = min, 1 = max)
+
+#pragma rs reduce(findMinAndMaxMat) \
+ initializer(fMinMaxMatInit) accumulator(fMinMaxMatAccumulator) \
+ combiner(fMinMaxMatCombiner) outconverter(fMinMaxMatOutConverter)
+
+typedef rs_matrix2x2 MatrixPair[2];
+enum MatrixPairEntry { MPE_Min = 0, MPE_Max = 1 }; // indices into MatrixPair
+
+static void fMinMaxMatInit(MatrixPair *accum) {
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ rsMatrixSet(&(*accum)[MPE_Min], i, j, posInf);
+ rsMatrixSet(&(*accum)[MPE_Max], i, j, negInf);
+ }
+ }
+}
+
+static void fMinMaxMatAccumulator(MatrixPair *accum, rs_matrix2x2 val) {
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ const float valElt = rsMatrixGet(&val, i, j);
+
+ const float minElt = rsMatrixGet(&(*accum)[MPE_Min], i, j);
+ if (valElt < minElt)
+ rsMatrixSet(&(*accum)[MPE_Min], i, j, valElt);
+
+ const float maxElt = rsMatrixGet(&(*accum)[MPE_Max], i, j);
+ if (valElt > maxElt)
+ rsMatrixSet(&(*accum)[MPE_Max], i, j, valElt);
+ }
+ }
+}
+
+static void fMinMaxMatCombiner(MatrixPair *accum, const MatrixPair *other) {
+ fMinMaxMatAccumulator(accum, (*other)[MPE_Min]);
+ fMinMaxMatAccumulator(accum, (*other)[MPE_Max]);
+}
+
+// reduction does not support matrix result, so use array instead
+static void fMinMaxMatOutConverter(float (*result)[8], const MatrixPair *accum) {
+ for (int i = 0; i < 4; ++i) {
+ (*result)[i+0] = (*accum)[MPE_Min].m[i];
+ (*result)[i+4] = (*accum)[MPE_Max].m[i];
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////
+
#pragma rs reduce(fz) \
initializer(fzInit) \
accumulator(fzAccum) combiner(fzCombine)
diff --git a/tests/tests/rsblas/AndroidTest.xml b/tests/tests/rsblas/AndroidTest.xml
index 19e6acc..340ca29 100644
--- a/tests/tests/rsblas/AndroidTest.xml
+++ b/tests/tests/rsblas/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.cts.rsblas" />
+ <option name="runtime-hint" value="12m57s" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 19547ff..c6ebf93 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -32,7 +32,7 @@
LOCAL_PACKAGE_NAME := CtsSecurityTestCases
-LOCAL_SDK_VERSION := 23
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index bf229e7..021abb2 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -35,15 +35,15 @@
android_security_cts_AudioFlingerBinderTest.cpp \
android_security_cts_AudioEffectBinderTest.cpp \
android_security_cts_MediaPlayerInfoLeakTest.cpp \
+ android_security_cts_StagefrightFoundationTest.cpp \
android_security_cts_GraphicBufferInfoLeakTest.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
$(TOP)/frameworks/native/include/media/openmax
-LOCAL_SHARED_LIBRARIES := libbinder libnativehelper_compat_libc++ liblog libdl libmedia libcrypto
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libbinder libutils libmedia libselinux libdl libcutils libcrypto libstagefright_foundation
LOCAL_C_INCLUDES += ndk/sources/cpufeatures
-LOCAL_STATIC_LIBRARIES := cpufeatures libselinux libutils libcutils
-LOCAL_CXX_STL := libc++_static
+LOCAL_STATIC_LIBRARIES := cpufeatures
include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 24c87b1..072f59e 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -29,6 +29,7 @@
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_StagefrightFoundationTest(JNIEnv* env);
extern int register_android_security_cts_GraphicBufferInfoLeakTest(JNIEnv* env);
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
@@ -90,6 +91,10 @@
return JNI_ERR;
}
+ if (register_android_security_cts_StagefrightFoundationTest(env)) {
+ return JNI_ERR;
+ }
+
if (register_android_security_cts_GraphicBufferInfoLeakTest(env)) {
return JNI_ERR;
}
diff --git a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
index 4c27416..6e94fce 100644
--- a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
@@ -119,7 +119,7 @@
descriptor.type = EFFECT_UIID_EQUALIZER;
descriptor.uuid = *EFFECT_UUID_NULL;
const int32_t priority = 0;
- const int sessionId = AUDIO_SESSION_OUTPUT_MIX;
+ 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;
diff --git a/tests/tests/security/jni/android_security_cts_StagefrightFoundationTest.cpp b/tests/tests/security/jni/android_security_cts_StagefrightFoundationTest.cpp
new file mode 100644
index 0000000..d16bd38
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_StagefrightFoundationTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 <cstdio>
+#include <jni.h>
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+using namespace android;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java
+ */
+
+static jboolean android_security_cts_StagefrightFoundation_test_aMessageFromParcel(
+ JNIEnv* env __unused, jobject thiz __unused)
+{
+ const int kMaxNumItems = 64;
+ const int kNumItems = kMaxNumItems + 1 + 1000;
+ char name[128];
+
+ Parcel data;
+ data.writeInt32(0); // what
+ data.writeInt32(kNumItems); // numItems
+ for (int i = 0; i < kMaxNumItems; ++i) {
+ snprintf(name, sizeof(name), "item-%d", i);
+ data.writeCString(name); // name
+ data.writeInt32(0); // kTypeInt32
+ data.writeInt32(i); // value
+ }
+ data.writeCString("evil"); // name
+ data.writeInt32(0); // kTypeInt32
+ data.writeInt32(0); // value
+ // NOTE: This could overwrite mNumItems!
+
+ for (int i = 0; i < 1000; ++i) {
+ snprintf(name, sizeof(name), "evil-%d", i);
+ data.writeCString(name); // name
+ data.writeInt32(0); // kTypeInt32
+ data.writeInt32(0); // value
+ }
+
+ data.setDataPosition(0);
+ sp<AMessage> msg = AMessage::FromParcel(data);
+
+ for (int i = 0; i < kMaxNumItems; ++i) {
+ snprintf(name, sizeof(name), "item-%d", i);
+ int32_t value;
+ if (!msg->findInt32(name, &value)) {
+ ALOGE("cannot find value for %s", name);
+ return JNI_FALSE;
+ }
+ if (value != i) {
+ ALOGE("value is changed: expected %d actual %d", i, value);
+ return JNI_FALSE;
+ }
+ }
+ return JNI_TRUE;
+}
+
+int register_android_security_cts_StagefrightFoundationTest(JNIEnv *env)
+{
+ static JNINativeMethod methods[] = {
+ { "native_test_aMessageFromParcel", "()Z",
+ (void *) android_security_cts_StagefrightFoundation_test_aMessageFromParcel},
+ };
+
+ jclass clazz = env->FindClass("android/security/cts/StagefrightFoundationTest");
+ return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
+}
diff --git a/tests/tests/security/src/android/security/cts/CertificateData.java b/tests/tests/security/src/android/security/cts/CertificateData.java
index ae216ad..f1116e7 100644
--- a/tests/tests/security/src/android/security/cts/CertificateData.java
+++ b/tests/tests/security/src/android/security/cts/CertificateData.java
@@ -106,7 +106,6 @@
"29:36:21:02:8B:20:ED:02:F5:66:C5:32:D1:D6:ED:90:9F:45:00:2F",
"37:9A:19:7B:41:85:45:35:0C:A6:03:69:F3:3C:2E:AF:47:4F:20:79",
"FA:B7:EE:36:97:26:62:FB:2D:B0:2A:F6:BF:03:FD:E8:7C:4B:2F:9B",
- "8B:AF:4C:9B:1D:F0:2A:92:F7:DA:12:8E:B9:1B:AC:F4:98:60:4B:6F",
"9F:74:4E:9F:2B:4D:BA:EC:0F:31:2C:50:B6:56:3B:8E:2D:93:C3:11",
"A1:4B:48:D9:43:EE:0A:0E:40:90:4F:3C:E0:A4:C0:91:93:51:5D:3F",
"C9:A8:B9:E7:55:80:5E:58:E3:53:77:A7:25:EB:AF:C3:7B:27:CC:D7",
diff --git a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
index 5298196..147a5cd 100644
--- a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
+++ b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
@@ -121,7 +121,9 @@
private void checkIfMediaServerDiedForDrm(int res) throws Exception {
if (!convertDmToFl(res, mFlFilePath)) {
- fail("Can not convert dm to fl");
+ Log.w(TAG, "Can not convert dm to fl, skip checkIfMediaServerDiedForDrm");
+ mMediaPlayer.release();
+ return;
}
Log.d(TAG, "intermediate fl file is " + mFlFilePath);
diff --git a/tests/tests/security/src/android/security/cts/RestrictedInformationTest.java b/tests/tests/security/src/android/security/cts/RestrictedInformationTest.java
deleted file mode 100644
index d0247e9..0000000
--- a/tests/tests/security/src/android/security/cts/RestrictedInformationTest.java
+++ /dev/null
@@ -1,64 +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.test.AndroidTestCase;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Enumeration;
-import android.content.pm.PackageManager;
-import android.net.wifi.WifiManager;
-import android.content.Context;
-
-/**
- * Check that restricted information is not available
- * to the untrusted_app domain
- */
-public class RestrictedInformationTest extends AndroidTestCase {
- /*
- * Test that wifi Mac address is not available through sysfs
- */
- public void testWifiMacAddr() throws Exception {
- /* if wifi does not exist, exit - PASS */
- PackageManager pm = getContext().getPackageManager();
- if (!pm.hasSystemFeature(PackageManager.FEATURE_WIFI))
- return;
-
- /* Wifi exists, but is not on - FAIL */
- WifiManager wifi = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
- assertTrue("Wifi must be enabled to pass this test.", wifi.isWifiEnabled());
-
- /* Enumerate through the interfaces */
- Enumeration<NetworkInterface> theInterfaces = NetworkInterface.getNetworkInterfaces();
-
- while (theInterfaces.hasMoreElements()) {
- NetworkInterface netif = theInterfaces.nextElement();
- String name = netif.getName();
- /* some devices label wifi network interface as eth */
- if (!name.contains("wlan") && !name.contains("eth"))
- continue;
- /* PASS means that getHardwareAddress throws a socket exception */
- try {
- byte[] hwAddr = netif.getHardwareAddress();
- fail("Mac address for " + name + "is accessible: " + new String(hwAddr) +
- "\nTo pass this test, label the address with the sysfs_mac_address\n" +
- "selinux label. " +
- "e.g. https://android-review.googlesource.com/#/c/162180/1\n");
- } catch (SocketException se) {/* socket exception if MAC blocked - PASS */}
- }
- }
-}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java b/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java
new file mode 100644
index 0000000..9999d88
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 StagefrightFoundationTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+ /**
+ * Checks that IEffect::command() cannot leak data.
+ */
+ public void test_aMessageFromParcel() throws Exception {
+ assertTrue(native_test_aMessageFromParcel());
+ }
+
+ private static native boolean native_test_aMessageFromParcel();
+}
diff --git a/tests/tests/systemui/AndroidTest.xml b/tests/tests/systemui/AndroidTest.xml
index d98dae6..61bdae3 100644
--- a/tests/tests/systemui/AndroidTest.xml
+++ b/tests/tests/systemui/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.systemui.cts" />
+ <option name="runtime-hint" value="10m19s" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/telecom/AndroidTest.xml b/tests/tests/telecom/AndroidTest.xml
index 03f64b3..7f34c0c 100644
--- a/tests/tests/telecom/AndroidTest.xml
+++ b/tests/tests/telecom/AndroidTest.xml
@@ -23,5 +23,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.telecom.cts" />
+ <option name="runtime-hint" value="10m20s" />
</test>
</configuration>
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 6810b71..8cf20bd 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -756,6 +756,24 @@
);
}
+ void assertDisconnectReason(final Connection connection, final String disconnectReason) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return disconnectReason;
+ }
+
+ @Override
+ public Object actual() {
+ return connection.getDisconnectCause().getReason();
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Connection should have been disconnected with reason: " + disconnectReason
+ );
+ }
+
void assertConferenceState(final Conference conference, final int state) {
waitUntilConditionIsTrueOrTimeout(
new Condition() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 7d71c0f..fbda2a3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -285,6 +285,29 @@
assertConnectionState(connection, Connection.STATE_DISCONNECTED);
}
+ public void testRejectIncomingCallWithMessage() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ String disconnectReason = "Test reason for disconnect";
+
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
+ final MockConnection connection = verifyConnectionForIncomingCall();
+
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+
+ final Call call = inCallService.getLastCall();
+
+ assertCallState(call, Call.STATE_RINGING);
+ assertConnectionState(connection, Connection.STATE_RINGING);
+
+ call.reject(true, disconnectReason);
+
+ assertCallState(call, Call.STATE_DISCONNECTED);
+ assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+ assertDisconnectReason(connection, disconnectReason);
+ }
+
public void testCanAddCall_CannotAddForExistingDialingCall() {
if (!mShouldTestTelecom) {
return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index 9bb83a1..fe33a8d 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -70,6 +70,16 @@
}
@Override
+ public void onReject(String reason) {
+ super.onReject();
+ setDisconnected(new DisconnectCause(DisconnectCause.REJECTED, reason));
+ if (mRemoteConnection != null) {
+ mRemoteConnection.reject();
+ }
+ destroy();
+ }
+
+ @Override
public void onHold() {
super.onHold();
setOnHold();
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index ad64e5c..48a1c94 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -73,6 +73,9 @@
ConnectionRequest request) {
final MockConnection connection = new MockConnection();
connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
+ connection.setConnectionCapabilities(
+ connection.getConnectionCapabilities() |
+ Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION);
connection.createMockVideoProvider();
((Connection) connection).setVideoState(request.getVideoState());
diff --git a/tests/tests/telephony/AndroidManifest.xml b/tests/tests/telephony/AndroidManifest.xml
index 6e9545a..e1905d1 100644
--- a/tests/tests/telephony/AndroidManifest.xml
+++ b/tests/tests/telephony/AndroidManifest.xml
@@ -34,6 +34,56 @@
<provider android:name="android.telephony.cts.MmsPduProvider"
android:authorities="telephonyctstest"
android:grantUriPermissions="true" />
+
+ <!-- SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ classes don't do anything, they are needed to make this a valid candidate for default SMS
+ app. -->
+ <!-- BroadcastReceiver that listens for incoming SMS messages -->
+ <receiver android:name=".SmsReceiver"
+ android:permission="android.permission.BROADCAST_SMS">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_DELIVER" />
+ </intent-filter>
+ </receiver>
+
+ <!-- BroadcastReceiver that listens for incoming MMS messages -->
+ <receiver android:name=".MmsReceiver"
+ android:permission="android.permission.BROADCAST_WAP_PUSH">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+ <data android:mimeType="application/vnd.wap.mms-message" />
+ </intent-filter>
+ </receiver>
+
+ <!-- Activity that allows the user to send new SMS/MMS messages -->
+ <activity android:name=".ComposeSmsActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <action android:name="android.intent.action.SENDTO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ </intent-filter>
+ </activity>
+
+ <!-- Service that delivers messages from the phone "quick response" -->
+ <service android:name=".HeadlessSmsSendService"
+ android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ </intent-filter>
+ </service>
+
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/telephony/src/android/telephony/cts/ComposeSmsActivity.java b/tests/tests/telephony/src/android/telephony/cts/ComposeSmsActivity.java
new file mode 100644
index 0000000..df1f0a9
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/ComposeSmsActivity.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.telephony.cts;
+
+import android.app.Activity;
+
+/**
+ * SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ * this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ * classes don't do anything, they are needed to make this a valid candidate for default SMS
+ * app. -->
+ */
+public class ComposeSmsActivity extends Activity {
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/HeadlessSmsSendService.java b/tests/tests/telephony/src/android/telephony/cts/HeadlessSmsSendService.java
new file mode 100644
index 0000000..f3fadb31
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/HeadlessSmsSendService.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 android.telephony.cts;
+
+import android.annotation.Nullable;
+import android.app.IntentService;
+import android.content.Intent;
+
+/**
+ * SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ * this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ * classes don't do anything, they are needed to make this a valid candidate for default SMS
+ * app. -->
+ */
+public class HeadlessSmsSendService extends IntentService {
+ /**
+ * Creates an IntentService. Invoked by your subclass's constructor.
+ *
+ * @param name Used to name the worker thread, important only for debugging.
+ */
+ public HeadlessSmsSendService(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void onHandleIntent(@Nullable Intent intent) {
+
+ }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsReceiver.java b/tests/tests/telephony/src/android/telephony/cts/MmsReceiver.java
new file mode 100644
index 0000000..d7d4b86
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsReceiver.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.telephony.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ * this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ * classes don't do anything, they are needed to make this a valid candidate for default SMS
+ * app. -->
+ */
+public class MmsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
index 6b72b82a..db7a974 100755
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -25,7 +25,7 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.SystemClock;
-import android.telephony.SmsManager;
+import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
@@ -57,6 +57,7 @@
private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION";
private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION";
private static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
+ public static final String SMS_DELIVER_DEFAULT_APP_ACTION = "CTS_SMS_DELIVERY_ACTION_DEFAULT_APP";
// List of network operators that don't support SMS delivery report
private static final List<String> NO_DELIVERY_REPORTS =
@@ -190,6 +191,8 @@
private SmsBroadcastReceiver mSendReceiver;
private SmsBroadcastReceiver mDeliveryReceiver;
private SmsBroadcastReceiver mDataSmsReceiver;
+ private SmsBroadcastReceiver mSmsDeliverReceiver;
+ private SmsBroadcastReceiver mSmsReceivedReceiver;
private PendingIntent mSentIntent;
private PendingIntent mDeliveredIntent;
private Intent mSendIntent;
@@ -254,7 +257,7 @@
return longText.equals(actualMessage);
}
- public void testSendMessages() throws InterruptedException {
+ public void testSendAndReceiveMessages() throws InterruptedException {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
@@ -267,16 +270,23 @@
IntentFilter sendIntentFilter = new IntentFilter(SMS_SEND_ACTION);
IntentFilter deliveryIntentFilter = new IntentFilter(SMS_DELIVERY_ACTION);
IntentFilter dataSmsReceivedIntentFilter = new IntentFilter(DATA_SMS_RECEIVED_ACTION);
+ IntentFilter smsDeliverIntentFilter = new IntentFilter(SMS_DELIVER_DEFAULT_APP_ACTION);
+ IntentFilter smsReceivedIntentFilter =
+ new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
dataSmsReceivedIntentFilter.addDataScheme("sms");
dataSmsReceivedIntentFilter.addDataAuthority("localhost", "19989");
mSendReceiver = new SmsBroadcastReceiver(SMS_SEND_ACTION);
mDeliveryReceiver = new SmsBroadcastReceiver(SMS_DELIVERY_ACTION);
mDataSmsReceiver = new SmsBroadcastReceiver(DATA_SMS_RECEIVED_ACTION);
+ mSmsDeliverReceiver = new SmsBroadcastReceiver(SMS_DELIVER_DEFAULT_APP_ACTION);
+ mSmsReceivedReceiver = new SmsBroadcastReceiver(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
getContext().registerReceiver(mSendReceiver, sendIntentFilter);
getContext().registerReceiver(mDeliveryReceiver, deliveryIntentFilter);
getContext().registerReceiver(mDataSmsReceiver, dataSmsReceivedIntentFilter);
+ getContext().registerReceiver(mSmsDeliverReceiver, smsDeliverIntentFilter);
+ getContext().registerReceiver(mSmsReceivedReceiver, smsReceivedIntentFilter);
// send single text sms
init();
@@ -285,6 +295,12 @@
if (mDeliveryReportSupported) {
assertTrue(mDeliveryReceiver.waitForCalls(1, TIME_OUT));
}
+ // non-default app should receive only SMS_RECEIVED_ACTION
+ assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0));
+
+ // due to permission restrictions, currently there is no way to make this test app the
+ // default SMS app
if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
// TODO: temp workaround, OCTET encoding for EMS not properly supported
@@ -326,6 +342,9 @@
if (mDeliveryReportSupported) {
assertTrue(mDeliveryReceiver.waitForCalls(numParts, TIME_OUT));
}
+ // non-default app should receive only SMS_RECEIVED_ACTION
+ assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0));
} else {
// This GSM network doesn't support Multipart SMS message.
// Skip the test.
@@ -336,6 +355,8 @@
mSendReceiver.reset();
mDeliveryReceiver.reset();
mDataSmsReceiver.reset();
+ mSmsDeliverReceiver.reset();
+ mSmsReceivedReceiver.reset();
mReceivedDataSms = false;
mSentIntent = PendingIntent.getBroadcast(getContext(), 0, mSendIntent,
PendingIntent.FLAG_ONE_SHOT);
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsReceiver.java b/tests/tests/telephony/src/android/telephony/cts/SmsReceiver.java
new file mode 100644
index 0000000..4fdadbb
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * 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.telephony.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Telephony;
+
+public class SmsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && intent.getAction().equals(Telephony.Sms.Intents.SMS_DELIVER_ACTION)) {
+ context.sendBroadcast(new Intent(SmsManagerTest.SMS_DELIVER_DEFAULT_APP_ACTION));
+ }
+ }
+}
diff --git a/tests/tests/text/res/layout/keylistener_layout.xml b/tests/tests/text/res/layout/keylistener_layout.xml
index 96a419d..cb8dbad 100644
--- a/tests/tests/text/res/layout/keylistener_layout.xml
+++ b/tests/tests/text/res/layout/keylistener_layout.xml
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keylistener_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
new file mode 100644
index 0000000..fa2e262
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.text.method.cts;
+
+import android.app.Activity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.InputType;
+import android.text.method.BaseKeyListener;
+import android.text.method.cts.KeyListenerTestCase;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test backspace key handling of {@link android.text.method.BaseKeyListner}.
+ */
+public class BackspaceTest extends KeyListenerTestCase {
+ private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
+ public int getInputType() {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ }
+ };
+
+ // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
+ // Then update the state to the result of TextView.
+ private void backspace(final EditorState state, int modifiers) {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setText(state.mText, BufferType.EDITABLE);
+ mTextView.setKeyListener(mKeyListener);
+ mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mTextView.hasWindowFocus());
+
+ final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ state.mText = mTextView.getText();
+ state.mSelectionStart = mTextView.getSelectionStart();
+ state.mSelectionEnd = mTextView.getSelectionEnd();
+ }
+
+ @SmallTest
+ public void testSurrogatePairs() {
+ EditorState state = new EditorState();
+
+ state.setByString("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F441 U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testReplacementSpan() {
+ EditorState state = new EditorState();
+
+ // ReplacementSpan will be set to "()" region.
+ state.setByString("'abc' ( 'de' ) 'fg' |");
+ backspace(state, 0);
+ state.assertEquals("'abc' ( 'de' ) 'f' |");
+ backspace(state, 0);
+ state.assertEquals("'abc' ( 'de' ) |");
+ backspace(state, 0);
+ state.assertEquals("'abc' |");
+ backspace(state, 0);
+ state.assertEquals("'ab' |");
+ backspace(state, 0);
+ state.assertEquals("'a' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'abc' [ ( 'de' ) ] 'fg'");
+ backspace(state, 0);
+ state.assertEquals("'abc' | 'fg'");
+ backspace(state, 0);
+ state.assertEquals("'ab' | 'fg'");
+ backspace(state, 0);
+ state.assertEquals("'a' | 'fg'");
+ backspace(state, 0);
+ state.assertEquals("| 'fg'");
+ backspace(state, 0);
+ state.assertEquals("| 'fg'");
+
+ state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'");
+ backspace(state, 0);
+ state.assertEquals("'ab' | 'g'");
+ backspace(state, 0);
+ state.assertEquals("'a' | 'g'");
+ backspace(state, 0);
+ state.assertEquals("| 'g'");
+ backspace(state, 0);
+ state.assertEquals("| 'g'");
+ }
+
+ @SmallTest
+ public void testCombiningEnclosingKeycaps() {
+ EditorState state = new EditorState();
+
+ // U+20E3 is COMBINING ENCLOSING KEYCAP.
+ state.setByString("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector before COMBINING ECLOSING KEYCAP
+ state.setByString("'1' U+FE0E U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testVariationSelector() {
+ EditorState state = new EditorState();
+
+ // U+FE0F is VARIATION SELECTOR-16.
+ state.setByString("'#' U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // U+E0100 is VARIATION SELECTOR-17.
+ state.setByString("U+845B U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testFlags() {
+ EditorState state = new EditorState();
+
+ // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
+ // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S.
+ state.setByString("U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'a' U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("'a' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F1FA U+1F1F8 U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'a' U+1F1FA U+1F1F8 'b' U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("'a' U+1F1FA U+1F1F8 'b' |");
+ backspace(state, 0);
+ state.assertEquals("'a' U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("'a' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+}
diff --git a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
index ba8bad5..8fa8780 100644
--- a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
@@ -535,17 +535,6 @@
listener.forwardDelete(mTextView, content, KeyEvent.KEYCODE_FORWARD_DEL, delKeyEvent);
}
- private KeyEvent getKey(int keycode, int metaState) {
- long currentTime = System.currentTimeMillis();
- return new KeyEvent(
- currentTime,
- currentTime,
- KeyEvent.ACTION_DOWN,
- keycode,
- 0 /* repeat */,
- metaState);
- }
-
/**
* Prepares mTextView state for tests by synchronously setting the content and key listener, on
* the UI thread.
diff --git a/tests/tests/text/src/android/text/method/cts/EditorState.java b/tests/tests/text/src/android/text/method/cts/EditorState.java
new file mode 100644
index 0000000..2a4f0b8
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/EditorState.java
@@ -0,0 +1,187 @@
+/*
+ * 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.text.method.cts;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ReplacementSpan;
+
+import junit.framework.Assert;
+
+/**
+ * Represents an editor state.
+ *
+ * The editor state can be specified by following string format.
+ * - Components are separated by space(U+0020).
+ * - Single-quoted string for printable ASCII characters, e.g. 'a', '123'.
+ * - U+XXXX form can be used for a Unicode code point.
+ * - Components inside '[' and ']' are in selection.
+ * - Components inside '(' and ')' are in ReplacementSpan.
+ * - '|' is for specifying cursor position.
+ *
+ * Selection and cursor can not be specified at the same time.
+ *
+ * Example:
+ * - "'Hello,' | U+0020 'world!'" means "Hello, world!" is displayed and the cursor position
+ * is 6.
+ * - "'abc' [ 'def' ] 'ghi'" means "abcdefghi" is displayed and "def" is selected.
+ * - "U+1F441 | ( U+1F441 U+1F441 )" means three U+1F441 characters are displayed and
+ * ReplacementSpan is set from offset 2 to 6.
+ */
+public class EditorState {
+ private static final String REPLACEMENT_SPAN_START = "(";
+ private static final String REPLACEMENT_SPAN_END = ")";
+ private static final String SELECTION_START = "[";
+ private static final String SELECTION_END = "]";
+ private static final String CURSOR = "|";
+
+ public Editable mText;
+ public int mSelectionStart = -1;
+ public int mSelectionEnd = -1;
+
+ public EditorState() {
+ }
+
+ /**
+ * A mocked {@link android.text.style.ReplacementSpan} for testing purpose.
+ */
+ private static class MockReplacementSpan extends ReplacementSpan {
+ public int getSize(Paint paint, CharSequence text, int start, int end,
+ Paint.FontMetricsInt fm) {
+ return 0;
+ }
+ public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+ int y, int bottom, Paint paint) {
+ }
+ }
+
+ // Returns true if the code point is ASCII and graph.
+ private boolean isGraphicAscii(int codePoint) {
+ return 0x20 < codePoint && codePoint < 0x7F;
+ }
+
+ // Setup editor state with string. Please see class description for string format.
+ public void setByString(String string) {
+ final StringBuilder sb = new StringBuilder();
+ int replacementSpanStart = -1;
+ int replacementSpanEnd = -1;
+ mSelectionStart = -1;
+ mSelectionEnd = -1;
+
+ final String[] tokens = string.split(" +");
+ for (String token : tokens) {
+ if (token.startsWith("'") && token.endsWith("'")) {
+ for (int i = 1; i < token.length() - 1; ++i) {
+ final char ch = token.charAt(1);
+ if (!isGraphicAscii(ch)) {
+ throw new IllegalArgumentException(
+ "Only printable characters can be in single quote. " +
+ "Use U+" + Integer.toHexString(ch).toUpperCase() + " instead");
+ }
+ }
+ sb.append(token.substring(1, token.length() - 1));
+ } else if (token.startsWith("U+")) {
+ final int codePoint = Integer.parseInt(token.substring(2), 16);
+ if (codePoint < 0 || 0x10FFFF < codePoint) {
+ throw new IllegalArgumentException("Invalid code point is specified:" + token);
+ }
+ sb.append(Character.toChars(codePoint));
+ } else if (token.equals(CURSOR)) {
+ if (mSelectionStart != -1 || mSelectionEnd != -1) {
+ throw new IllegalArgumentException(
+ "Two or more cursor/selection positions are specified.");
+ }
+ mSelectionStart = mSelectionEnd = sb.length();
+ } else if (token.equals(SELECTION_START)) {
+ if (mSelectionStart != -1) {
+ throw new IllegalArgumentException(
+ "Two or more cursor/selection positions are specified.");
+ }
+ mSelectionStart = sb.length();
+ } else if (token.equals(SELECTION_END)) {
+ if (mSelectionEnd != -1) {
+ throw new IllegalArgumentException(
+ "Two or more cursor/selection positions are specified.");
+ }
+ mSelectionEnd = sb.length();
+ } else if (token.equals(REPLACEMENT_SPAN_START)) {
+ if (replacementSpanStart != -1) {
+ throw new IllegalArgumentException(
+ "Only one replacement span is supported");
+ }
+ replacementSpanStart = sb.length();
+ } else if (token.equals(REPLACEMENT_SPAN_END)) {
+ if (replacementSpanEnd != -1) {
+ throw new IllegalArgumentException(
+ "Only one replacement span is supported");
+ }
+ replacementSpanEnd = sb.length();
+ } else {
+ throw new IllegalArgumentException("Unknown or invalid token: " + token);
+ }
+ }
+
+ if (mSelectionStart == -1 || mSelectionEnd == -1) {
+ if (mSelectionEnd != -1) {
+ throw new IllegalArgumentException(
+ "Selection start position doesn't exist.");
+ } else if (mSelectionStart != -1) {
+ throw new IllegalArgumentException(
+ "Selection end position doesn't exist.");
+ } else {
+ throw new IllegalArgumentException(
+ "At least cursor position or selection range must be specified.");
+ }
+ } else if (mSelectionStart > mSelectionEnd) {
+ throw new IllegalArgumentException(
+ "Selection start position appears after end position.");
+ }
+
+ final Spannable spannable = new SpannableString(sb.toString());
+
+ if (replacementSpanStart != -1 || replacementSpanEnd != -1) {
+ if (replacementSpanStart == -1) {
+ throw new IllegalArgumentException(
+ "ReplacementSpan start position doesn't exist.");
+ }
+ if (replacementSpanEnd == -1) {
+ throw new IllegalArgumentException(
+ "ReplacementSpan end position doesn't exist.");
+ }
+ if (replacementSpanStart > replacementSpanEnd) {
+ throw new IllegalArgumentException(
+ "ReplacementSpan start position appears after end position.");
+ }
+ spannable.setSpan(new MockReplacementSpan(), replacementSpanStart, replacementSpanEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ mText = Editable.Factory.getInstance().newEditable(spannable);
+ }
+
+ public void assertEquals(String string) {
+ EditorState expected = new EditorState();
+ expected.setByString(string);
+
+ Assert.assertEquals(expected.mText.toString(), mText.toString());
+ Assert.assertEquals(expected.mSelectionStart, mSelectionStart);
+ Assert.assertEquals(expected.mSelectionEnd, mSelectionEnd);
+ }
+}
+
diff --git a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
new file mode 100644
index 0000000..47c2795
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.text.method.cts;
+
+import android.app.Activity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.InputType;
+import android.text.method.BaseKeyListener;
+import android.text.method.cts.KeyListenerTestCase;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test forward delete key handling of {@link android.text.method.BaseKeyListener}.
+ */
+public class ForwardDeleteTest extends KeyListenerTestCase {
+ private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
+ public int getInputType() {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ }
+ };
+
+ // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
+ // Then update the state to the result of TextView.
+ private void forwardDelete(final EditorState state, int modifiers) {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setText(state.mText, BufferType.EDITABLE);
+ mTextView.setKeyListener(mKeyListener);
+ mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mTextView.hasWindowFocus());
+
+ final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ state.mText = mTextView.getText();
+ state.mSelectionStart = mTextView.getSelectionStart();
+ state.mSelectionEnd = mTextView.getSelectionEnd();
+ }
+
+ @SmallTest
+ public void testSurrogatePairs() {
+ EditorState state = new EditorState();
+
+ // U+1F441 is EYE
+ state.setByString("| U+1F441");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // U+1F5E8 is LEFT SPEECH BUBBLE
+ state.setByString("| U+1F441 U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testReplacementSpan() {
+ EditorState state = new EditorState();
+
+ state.setByString("| 'abc' ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'bc' ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'c' ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'abc' [ ( 'de' ) ] 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' | 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' | 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' |");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' |");
+
+ state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("'ab' | 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("'ab' |");
+ forwardDelete(state, 0);
+ state.assertEquals("'ab' |");
+ }
+
+ @SmallTest
+ public void testCombiningEnclosingKeycaps() {
+ EditorState state = new EditorState();
+
+ // U+20E3 is COMBINING ENCLOSING KEYCAP.
+ state.setByString("| '1' U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| '1' U+FE0F U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testVariationSelector() {
+ EditorState state = new EditorState();
+
+ // U+FE0F is VARIATION SELECTOR-16.
+ state.setByString("| '#' U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // U+E0100 is VARIATION SELECTOR-17.
+ state.setByString("| U+845B U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testFlags() {
+ EditorState state = new EditorState();
+
+ // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
+ // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S.
+ state.setByString("| U+1F1FA U+1F1F8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+1F1FA U+1F1F8 U+1F1FA U+1F1F8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA U+1F1F8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+}
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
index 4f89ff3..313d380 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
@@ -23,8 +23,9 @@
import android.text.format.DateUtils;
import android.text.method.cts.KeyListenerCtsActivity;
import android.text.method.KeyListener;
+import android.view.KeyEvent;
import android.view.WindowManager;
-import android.widget.TextView;
+import android.widget.EditText;
/**
* Base class for various KeyListener tests.
@@ -50,7 +51,7 @@
ActivityInstrumentationTestCase2<KeyListenerCtsActivity> {
protected KeyListenerCtsActivity mActivity;
protected Instrumentation mInstrumentation;
- protected TextView mTextView;
+ protected EditText mTextView;
public KeyListenerTestCase() {
super("com.android.cts.text", KeyListenerCtsActivity.class);
@@ -62,7 +63,7 @@
mActivity = getActivity();
mInstrumentation = getInstrumentation();
- mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
+ mTextView = (EditText) mActivity.findViewById(R.id.keylistener_textview);
mActivity.runOnUiThread(new Runnable() {
public void run() {
@@ -85,4 +86,10 @@
});
mInstrumentation.waitForIdleSync();
}
+
+ protected static KeyEvent getKey(int keycode, int metaState) {
+ long currentTime = System.currentTimeMillis();
+ return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode,
+ 0 /* repeat */, metaState);
+ }
}
diff --git a/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java b/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java
index bdd3d17..e825bd1 100644
--- a/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java
@@ -47,6 +47,14 @@
assertEquals(-5, absoluteSizeSpan.getSize());
}
+ public void testGetDip() {
+ AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(5);
+ assertEquals(false, absoluteSizeSpan.getDip());
+
+ absoluteSizeSpan = new AbsoluteSizeSpan(5, true);
+ assertEquals(true, absoluteSizeSpan.getDip());
+ }
+
public void testUpdateMeasureState() {
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(1);
diff --git a/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java b/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java
new file mode 100644
index 0000000..7405107
--- /dev/null
+++ b/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.text.style.cts;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.style.EasyEditSpan;
+
+public class EasyEditSpanTest extends AndroidTestCase {
+ @SmallTest
+ public void testConstructor() {
+ new EasyEditSpan();
+ new EasyEditSpan(PendingIntent.getActivity(getContext(), 0, new Intent(), 0));
+ Parcel p = Parcel.obtain();
+ try {
+ new EasyEditSpan(p);
+ } finally {
+ p.recycle();
+ }
+ }
+
+ @SmallTest
+ public void testDescribeContents_doesNotThrowException() {
+ EasyEditSpan easyEditSpan = new EasyEditSpan();
+ easyEditSpan.describeContents();
+ }
+
+ @SmallTest
+ public void testGetSpanTypeId_doesNotThrowException() {
+ EasyEditSpan easyEditSpan = new EasyEditSpan();
+ easyEditSpan.getSpanTypeId();
+ }
+
+ @SmallTest
+ public void testWriteToParcel() {
+ Parcel p = Parcel.obtain();
+ try {
+ EasyEditSpan easyEditSpan = new EasyEditSpan();
+ easyEditSpan.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ new EasyEditSpan(p);
+ } finally {
+ p.recycle();
+ }
+ }
+}
diff --git a/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java b/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java
index bc93e41..f44cca5 100644
--- a/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java
@@ -17,9 +17,10 @@
package android.text.style.cts;
import junit.framework.TestCase;
-
import android.annotation.NonNull;
import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextPaint;
import android.text.style.LocaleSpan;
import android.util.LocaleList;
@@ -35,6 +36,7 @@
assertEquals(locales, cloned.getLocales());
}
+ @SmallTest
public void testGetLocales() {
checkGetLocales(LocaleList.getEmptyLocaleList());
checkGetLocales(LocaleList.forLanguageTags("en"));
@@ -42,6 +44,7 @@
checkGetLocales(LocaleList.forLanguageTags("de-DE-u-co-phonebk,en-GB,en"));
}
+ @SmallTest
public void testConstructorWithLocaleList() {
try {
new LocaleSpan((LocaleList) null);
@@ -66,4 +69,48 @@
}
}
}
+
+ @SmallTest
+ public void testDescribeContents_doesNotThrowException() {
+ LocaleSpan localeSpan = new LocaleSpan(LocaleList.getEmptyLocaleList());
+ localeSpan.describeContents();
+ }
+
+ @SmallTest
+ public void testGetSpanTypeId_doesNotThrowException() {
+ LocaleSpan localeSpan = new LocaleSpan(LocaleList.getEmptyLocaleList());
+ localeSpan.getSpanTypeId();
+ }
+
+ @SmallTest
+ public void testUpdateDrawState() {
+ LocaleList localeListForSpan = LocaleList.forLanguageTags("en");
+ LocaleSpan localeSpan = new LocaleSpan(localeListForSpan);
+
+ TextPaint tp = new TextPaint();
+ LocaleList localeList = LocaleList.forLanguageTags("fr,de");
+ tp.setTextLocales(localeList);
+ assertEquals(localeList, tp.getTextLocales());
+ assertEquals(localeList.get(0), tp.getTextLocale());
+
+ localeSpan.updateDrawState(tp);
+ assertEquals(localeListForSpan, tp.getTextLocales());
+ assertEquals(localeListForSpan.get(0), tp.getTextLocale());
+ }
+
+ @SmallTest
+ public void testUpdateMeasureState() {
+ LocaleList localeListForSpan = LocaleList.forLanguageTags("en");
+ LocaleSpan localeSpan = new LocaleSpan(localeListForSpan);
+
+ TextPaint tp = new TextPaint();
+ LocaleList localeList = LocaleList.forLanguageTags("fr,de");
+ tp.setTextLocales(localeList);
+ assertEquals(localeList, tp.getTextLocales());
+ assertEquals(localeList.get(0), tp.getTextLocale());
+
+ localeSpan.updateMeasureState(tp);
+ assertEquals(localeListForSpan, tp.getTextLocales());
+ assertEquals(localeListForSpan.get(0), tp.getTextLocale());
+ }
}
diff --git a/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java b/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
index 3c320f1..c718a37 100644
--- a/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.PersistableBundle;
+import android.test.suitebuilder.annotation.SmallTest;
import android.text.style.TtsSpan;
import junit.framework.TestCase;
@@ -25,6 +26,7 @@
PersistableBundle bundle;
+ @Override
protected void setUp() {
bundle = new PersistableBundle();
bundle.putString("argument.one", "value.one");
@@ -33,6 +35,7 @@
bundle.putLong("argument.four", 4);
}
+ @SmallTest
public void testGetArgs() {
TtsSpan t = new TtsSpan("test.type.one", bundle);
PersistableBundle args = t.getArgs();
@@ -43,21 +46,25 @@
assertEquals(4, args.getLong("argument.four"));
}
+ @SmallTest
public void testGetType() {
TtsSpan t = new TtsSpan("test.type.two", bundle);
assertEquals("test.type.two", t.getType());
}
+ @SmallTest
public void testDescribeContents() {
TtsSpan span = new TtsSpan("test.type.three", bundle);
span.describeContents();
}
+ @SmallTest
public void testGetSpanTypeId() {
TtsSpan span = new TtsSpan("test.type.four", bundle);
span.getSpanTypeId();
}
+ @SmallTest
public void testWriteAndReadParcel() {
Parcel p = Parcel.obtain();
try {
@@ -78,4 +85,423 @@
p.recycle();
}
}
+
+ @SmallTest
+ public void testBuilder() {
+ final TtsSpan t = (new TtsSpan.Builder<>("test.type.builder"))
+ .setStringArgument("argument.string", "value")
+ .setIntArgument("argument.int", Integer.MAX_VALUE)
+ .setLongArgument("argument.long", Long.MAX_VALUE)
+ .build();
+ assertEquals("test.type.builder", t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(3, args.size());
+ assertEquals("value", args.getString("argument.string"));
+ assertEquals(Integer.MAX_VALUE, args.getInt("argument.int"));
+ assertEquals(Long.MAX_VALUE, args.getLong("argument.long"));
+ }
+
+ @SmallTest
+ public void testSemioticClassBuilder() {
+ final TtsSpan t = (new TtsSpan.SemioticClassBuilder<>("test.type.semioticClassBuilder"))
+ .setGender(TtsSpan.GENDER_FEMALE)
+ .setAnimacy(TtsSpan.ANIMACY_ANIMATE)
+ .setMultiplicity(TtsSpan.MULTIPLICITY_SINGLE)
+ .setCase(TtsSpan.CASE_NOMINATIVE)
+ .build();
+ assertEquals("test.type.semioticClassBuilder", t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(4, args.size());
+ assertEquals(TtsSpan.GENDER_FEMALE, args.getString(TtsSpan.ARG_GENDER));
+ assertEquals(TtsSpan.ANIMACY_ANIMATE, args.getString(TtsSpan.ARG_ANIMACY));
+ assertEquals(TtsSpan.MULTIPLICITY_SINGLE, args.getString(TtsSpan.ARG_MULTIPLICITY));
+ assertEquals(TtsSpan.CASE_NOMINATIVE, args.getString(TtsSpan.ARG_CASE));
+ }
+
+ @SmallTest
+ public void testTextBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.TextBuilder())
+ .setText("text")
+ .build();
+ assertEquals(TtsSpan.TYPE_TEXT, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("text", args.getString(TtsSpan.ARG_TEXT));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.TextBuilder("text")).build();
+ assertEquals(TtsSpan.TYPE_TEXT, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("text", args.getString(TtsSpan.ARG_TEXT));
+ }
+ }
+
+ @SmallTest
+ public void testCardinalBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.CardinalBuilder())
+ .setNumber(Long.MAX_VALUE)
+ .build();
+ assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.CardinalBuilder())
+ .setNumber("10")
+ .build();
+ assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.CardinalBuilder(Long.MAX_VALUE)).build();
+ assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.CardinalBuilder("10")).build();
+ assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
+ }
+ }
+
+ @SmallTest
+ public void testOrdinalBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.OrdinalBuilder())
+ .setNumber(Long.MAX_VALUE)
+ .build();
+ assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.OrdinalBuilder())
+ .setNumber("10")
+ .build();
+ assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.OrdinalBuilder(Long.MAX_VALUE)).build();
+ assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.OrdinalBuilder("10")).build();
+ assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
+ }
+ }
+
+ @SmallTest
+ public void testDecimalBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.DecimalBuilder())
+ .setArgumentsFromDouble(10.25, 1, 2)
+ .build();
+ assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DecimalBuilder(10.25, 1, 2)).build();
+ assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DecimalBuilder())
+ .setArgumentsFromDouble(10, 0, 0)
+ .build();
+ assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DecimalBuilder(10, 0, 0)).build();
+ assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DecimalBuilder())
+ .setArgumentsFromDouble(10.25, 10, 10)
+ .build();
+ assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("2500000000", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+ }
+ }
+
+ @SmallTest
+ public void testFractionBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.FractionBuilder())
+ .setIntegerPart(10)
+ .setNumerator(3)
+ .setDenominator(100)
+ .build();
+ assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(3, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
+ assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.FractionBuilder(10, 3, 100)).build();
+ assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(3, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
+ assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
+ }
+ }
+
+ @SmallTest
+ public void testMeasureBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.MeasureBuilder())
+ .setNumber(10)
+ .setUnit("unit")
+ .build();
+ assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
+ assertEquals("unit", args.getString(TtsSpan.ARG_UNIT));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.MeasureBuilder())
+ .setIntegerPart(10)
+ .setFractionalPart("25")
+ .setUnit("unit")
+ .build();
+ assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(3, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+ assertEquals("unit", args.getString(TtsSpan.ARG_UNIT));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.MeasureBuilder())
+ .setIntegerPart(10)
+ .setNumerator(3)
+ .setDenominator(100)
+ .setUnit("unit")
+ .build();
+ assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(4, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
+ assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
+ assertEquals("unit", args.getString(TtsSpan.ARG_UNIT));
+ }
+ }
+
+ @SmallTest
+ public void testTimeBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.TimeBuilder())
+ .setHours(20)
+ .setMinutes(50)
+ .build();
+ assertEquals(TtsSpan.TYPE_TIME, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals(20, args.getInt(TtsSpan.ARG_HOURS));
+ assertEquals(50, args.getInt(TtsSpan.ARG_MINUTES));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.TimeBuilder(20, 50)).build();
+ assertEquals(TtsSpan.TYPE_TIME, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals(20, args.getInt(TtsSpan.ARG_HOURS));
+ assertEquals(50, args.getInt(TtsSpan.ARG_MINUTES));
+ }
+ }
+
+ @SmallTest
+ public void testDateBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.DateBuilder())
+ .setWeekday(3)
+ .setDay(16)
+ .setMonth(3)
+ .setYear(2016)
+ .build();
+ assertEquals(TtsSpan.TYPE_DATE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(4, args.size());
+ assertEquals(3, args.getInt(TtsSpan.ARG_WEEKDAY));
+ assertEquals(16, args.getInt(TtsSpan.ARG_DAY));
+ assertEquals(3, args.getInt(TtsSpan.ARG_MONTH));
+ assertEquals(2016, args.getInt(TtsSpan.ARG_YEAR));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DateBuilder(3, 16, 3, 2016)).build();
+ assertEquals(TtsSpan.TYPE_DATE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(4, args.size());
+ assertEquals(3, args.getInt(TtsSpan.ARG_WEEKDAY));
+ assertEquals(16, args.getInt(TtsSpan.ARG_DAY));
+ assertEquals(3, args.getInt(TtsSpan.ARG_MONTH));
+ assertEquals(2016, args.getInt(TtsSpan.ARG_YEAR));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DateBuilder(3, 16, null, null)).build();
+ assertEquals(TtsSpan.TYPE_DATE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals(3, args.getInt(TtsSpan.ARG_WEEKDAY));
+ assertEquals(16, args.getInt(TtsSpan.ARG_DAY));
+ }
+ }
+
+ @SmallTest
+ public void testMoneyBuilder() {
+ final TtsSpan t = (new TtsSpan.MoneyBuilder())
+ .setIntegerPart(10)
+ .setFractionalPart("25")
+ .setCurrency("USD")
+ .setQuantity("1000")
+ .build();
+ assertEquals(TtsSpan.TYPE_MONEY, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(4, args.size());
+ assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+ assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+ assertEquals("USD", args.getString(TtsSpan.ARG_CURRENCY));
+ assertEquals("1000", args.getString(TtsSpan.ARG_QUANTITY));
+ }
+
+ @SmallTest
+ public void testTelephoneBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.TelephoneBuilder())
+ .setCountryCode("+01")
+ .setNumberParts("000-000-0000")
+ .setExtension("0000")
+ .build();
+ assertEquals(TtsSpan.TYPE_TELEPHONE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(3, args.size());
+ assertEquals("+01", args.getString(TtsSpan.ARG_COUNTRY_CODE));
+ assertEquals("000-000-0000", args.getString(TtsSpan.ARG_NUMBER_PARTS));
+ assertEquals("0000", args.getString(TtsSpan.ARG_EXTENSION));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.TelephoneBuilder("000-000-0000")).build();
+ assertEquals(TtsSpan.TYPE_TELEPHONE, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("000-000-0000", args.getString(TtsSpan.ARG_NUMBER_PARTS));
+ }
+ }
+
+ @SmallTest
+ public void testElectronicBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.ElectronicBuilder())
+ .setEmailArguments("example", "example.com")
+ .build();
+ assertEquals(TtsSpan.TYPE_ELECTRONIC, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(2, args.size());
+ assertEquals("example", args.getString(TtsSpan.ARG_USERNAME));
+ assertEquals("example.com", args.getString(TtsSpan.ARG_DOMAIN));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.ElectronicBuilder())
+ .setProtocol("http")
+ .setDomain("example.com")
+ .setPort(80)
+ .setPath("example/index.html")
+ .setQueryString("arg1=value1&arg2=value2")
+ .setFragmentId("fragment")
+ .setUsername("username")
+ .setPassword("password")
+ .build();
+ assertEquals(TtsSpan.TYPE_ELECTRONIC, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(8, args.size());
+ assertEquals("http", args.getString(TtsSpan.ARG_PROTOCOL));
+ assertEquals("example.com", args.getString(TtsSpan.ARG_DOMAIN));
+ assertEquals(80, args.getInt(TtsSpan.ARG_PORT));
+ assertEquals("example/index.html", args.getString(TtsSpan.ARG_PATH));
+ assertEquals("arg1=value1&arg2=value2", args.getString(TtsSpan.ARG_QUERY_STRING));
+ assertEquals("fragment", args.getString(TtsSpan.ARG_FRAGMENT_ID));
+ assertEquals("username", args.getString(TtsSpan.ARG_USERNAME));
+ assertEquals("password", args.getString(TtsSpan.ARG_PASSWORD));
+ }
+ }
+
+ @SmallTest
+ public void testDigitsBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.DigitsBuilder())
+ .setDigits("12345")
+ .build();
+ assertEquals(TtsSpan.TYPE_DIGITS, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("12345", args.getString(TtsSpan.ARG_DIGITS));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.DigitsBuilder("12345")).build();
+ assertEquals(TtsSpan.TYPE_DIGITS, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("12345", args.getString(TtsSpan.ARG_DIGITS));
+ }
+ }
+
+ @SmallTest
+ public void testVerbatimBuilder() {
+ {
+ final TtsSpan t = (new TtsSpan.VerbatimBuilder())
+ .setVerbatim("abcdefg")
+ .build();
+ assertEquals(TtsSpan.TYPE_VERBATIM, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("abcdefg", args.getString(TtsSpan.ARG_VERBATIM));
+ }
+ {
+ final TtsSpan t = (new TtsSpan.VerbatimBuilder("abcdefg")).build();
+ assertEquals(TtsSpan.TYPE_VERBATIM, t.getType());
+ PersistableBundle args = t.getArgs();
+ assertEquals(1, args.size());
+ assertEquals("abcdefg", args.getString(TtsSpan.ARG_VERBATIM));
+ }
+ }
}
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index c0d16de..00f624f 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -25,6 +25,7 @@
import android.text.util.Linkify;
import android.text.util.Linkify.MatchFilter;
import android.text.util.Linkify.TransformFilter;
+import android.util.Patterns;
import android.widget.TextView;
import java.util.Locale;
@@ -351,6 +352,110 @@
assertFalse(Linkify.addLinks((Spannable) null, 0));
}
+ @SmallTest
+ public void testAddLinks_addsLinksWhenDefaultSchemeIsNull() {
+ Spannable spannable = new SpannableString("any https://android.com any android.com any");
+ Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, null, null, null);
+
+ URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+ assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
+ assertEquals("https://android.com", spans[0].getURL());
+ assertEquals("android.com", spans[1].getURL());
+ }
+
+ @SmallTest
+ public void testAddLinks_addsLinksWhenSchemesArrayIsNull() {
+ Spannable spannable = new SpannableString("any https://android.com any android.com any");
+ Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://", null, null);
+
+ URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+ assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
+ // expected behavior, passing null schemes array means: prepend defaultScheme to all links.
+ assertEquals("http://https://android.com", spans[0].getURL());
+ assertEquals("http://android.com", spans[1].getURL());
+ }
+
+ @SmallTest
+ public void testAddLinks_prependsDefaultSchemeToBeginingOfLink() {
+ Spannable spannable = new SpannableString("any android.com any");
+ Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://",
+ new String[] { "http://", "https://"}, null, null);
+
+ URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+ assertEquals("android.com should be linkified", 1, spans.length);
+ assertEquals("http://android.com", spans[0].getURL());
+ }
+
+ @SmallTest
+ public void testAddLinks_doesNotPrependSchemeIfSchemeExists() {
+ Spannable spannable = new SpannableString("any https://android.com any");
+ Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://",
+ new String[] { "http://", "https://"}, null, null);
+
+ URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+ assertEquals("android.com should be linkified", 1, spans.length);
+ assertEquals("https://android.com", spans[0].getURL());
+ }
+
+ // Add links with scheme (array)
+
+ @SmallTest
+ public void testAddLinks_withTextView_addsLinksWhenDefaultSchemeIsNull() {
+ Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
+ TextView textView = new TextView(mContext);
+ textView.setText("any https://android.com any android.com any");
+
+ Linkify.addLinks(textView, pattern, null, null, null);
+
+ URLSpan[] spans = textView.getUrls();
+ assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
+ assertEquals("https://android.com", spans[0].getURL());
+ assertEquals("android.com", spans[1].getURL());
+ }
+
+ @SmallTest
+ public void testAddLinks_withTextView_addsLinksWhenSchemesArrayIsNull() {
+ Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
+ TextView textView = new TextView(mContext);
+ textView.setText("any https://android.com any android.com any");
+
+ Linkify.addLinks(textView, pattern, "http://", null, null);
+
+ URLSpan[] spans = textView.getUrls();
+ assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
+ // expected behavior, passing null schemes array means: prepend defaultScheme to all links.
+ assertEquals("http://https://android.com", spans[0].getURL());
+ assertEquals("http://android.com", spans[1].getURL());
+ }
+
+ @SmallTest
+ public void testAddLinks_withTextView_prependsDefaultSchemeToBeginingOfLink() {
+ Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
+ TextView textView = new TextView(mContext);
+ textView.setText("any android.com any");
+
+ Linkify.addLinks(textView, pattern, "http://", new String[] { "http://", "https://"},
+ null, null);
+
+ URLSpan[] spans = textView.getUrls();
+ assertEquals("android.com should be linkified", 1, spans.length);
+ assertEquals("http://android.com", spans[0].getURL());
+ }
+
+ @SmallTest
+ public void testAddLinks_withTextView_doesNotPrependSchemeIfSchemeExists() {
+ Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
+ TextView textView = new TextView(mContext);
+ textView.setText("any https://android.com any");
+
+ Linkify.addLinks(textView, pattern, "http://", new String[] { "http://", "https://"},
+ null, null);
+
+ URLSpan[] spans = textView.getUrls();
+ assertEquals("android.com should be linkified", 1, spans.length);
+ assertEquals("https://android.com", spans[0].getURL());
+ }
+
// WEB_URLS Related Tests
@SmallTest
diff --git a/tests/tests/theme/Android.mk b/tests/tests/theme/Android.mk
index 0f370d0..8b69a09 100644
--- a/tests/tests/theme/Android.mk
+++ b/tests/tests/theme/Android.mk
@@ -24,7 +24,8 @@
# When built, explicitly put it in the data partition.
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctstestrunner platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java b/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java
index 77de0b4..fdac2d1 100644
--- a/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java
+++ b/tests/tests/theme/src/android/theme/cts/DeviceDefaultTest.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.platform.test.annotations.Presubmit;
import android.test.ActivityInstrumentationTestCase2;
public class DeviceDefaultTest extends ActivityInstrumentationTestCase2<DeviceDefaultActivity> {
@@ -57,6 +58,7 @@
assertNoActionBar(android.R.style.Theme_DeviceDefault_DialogWhenLarge_NoActionBar);
}
+ @Presubmit
public void testGetActionBar_DeviceDefault_InputMethod() {
assertNoActionBar(android.R.style.Theme_DeviceDefault_InputMethod);
}
diff --git a/tests/tests/transition/res/layout/scene10.xml b/tests/tests/transition/res/layout/scene10.xml
new file mode 100644
index 0000000..16e3c20
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene10.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:transitionName="holder"
+ android:id="@+id/holder">
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#F00"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:id="@+id/redSquare" />
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#0F0"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:id="@+id/greenSquare"/>
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#00F"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentBottom="true"
+ android:id="@+id/blueSquare" />
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#FF0"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:id="@+id/yellowSquare"/>
+</RelativeLayout>
diff --git a/tests/tests/transition/res/layout/scene9.xml b/tests/tests/transition/res/layout/scene9.xml
new file mode 100644
index 0000000..2eb3762f
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene9.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:transitionName="holder"
+ android:id="@+id/holder">
+ <FrameLayout
+ android:layout_marginTop="50dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/text"
+ android:text="@string/longText"
+ android:layout_width="100dp"
+ android:layout_height="100dp"/>
+ </FrameLayout>
+</RelativeLayout>
diff --git a/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java b/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java
index 6cb5c1c..d6b00cf 100644
--- a/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java
@@ -21,7 +21,7 @@
import junit.framework.TestCase;
-public class ArcMotionTest extends TestCase {
+public class ArcMotionTest extends PathMotionTest {
public void test90Quadrants() throws Throwable {
ArcMotion arcMotion = new ArcMotion();
@@ -96,29 +96,6 @@
return path;
}
- private void assertPathMatches(Path expectedPath, Path path) {
- PathMeasure expectedMeasure = new PathMeasure(expectedPath, false);
- PathMeasure pathMeasure = new PathMeasure(path, false);
-
- float expectedLength = expectedMeasure.getLength();
- assertEquals(expectedLength, pathMeasure.getLength(), 0.01f);
-
- float minLength = Math.min(expectedLength, pathMeasure.getLength());
-
- float pos[] = new float[2];
-
- float increment = minLength / 5f;
- for (float along = 0; along <= minLength; along += increment) {
- expectedMeasure.getPosTan(along, pos, null);
- float expectedX = pos[0];
- float expectedY = pos[1];
-
- pathMeasure.getPosTan(along, pos, null);
- assertEquals(expectedX, pos[0], 0.01f);
- assertEquals(expectedY, pos[1], 0.01f);
- }
- }
-
public void testMaximumAngle() throws Throwable {
ArcMotion arcMotion = new ArcMotion();
arcMotion.setMaximumAngle(45f);
diff --git a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
index 56ba44b..944ff91 100644
--- a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
@@ -164,24 +164,6 @@
mTransition.addListener(mListener);
}
- // Waits at least one frame and it could be more. The animated values should have changed
- // from the previously recorded values by the end of this method.
- protected void waitForAnimationFrame() throws Throwable {
- final CountDownLatch latch = new CountDownLatch(1);
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- Choreographer.getInstance().postFrameCallbackDelayed(new FrameCallback() {
- @Override
- public void doFrame(long frameTimeNanos) {
- latch.countDown();
- }
- }, 16); // make sure it is the next animation frame.
- }
- });
- assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
- }
-
public class TestTransition extends Visibility {
public TestTransition() {
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
index a99f175..d5c1245 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
@@ -18,7 +18,6 @@
import android.content.res.Resources;
import android.graphics.Rect;
import android.transition.ChangeBounds;
-import android.transition.cts.R;
import android.util.TypedValue;
import android.view.View;
@@ -62,7 +61,9 @@
}
public void testResizeClip() throws Throwable {
+ assertEquals(false, mChangeBounds.getResizeClip());
mChangeBounds.setResizeClip(true);
+ assertEquals(true, mChangeBounds.getResizeClip());
enterScene(R.layout.scene1);
validateInScene1();
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.java
new file mode 100644
index 0000000..9411d29
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.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 android.transition.cts;
+
+import android.graphics.Rect;
+import android.transition.ChangeClipBounds;
+import android.transition.TransitionManager;
+import android.view.View;
+
+public class ChangeClipBoundsTest extends BaseTransitionTest {
+ private ChangeClipBounds mChangeClipBounds;
+
+ public ChangeClipBoundsTest() {
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mChangeClipBounds = new ChangeClipBounds();
+ mTransition = mChangeClipBounds;
+ resetListener();
+ }
+
+ public void testChangeClipBounds() throws Throwable {
+ enterScene(R.layout.scene1);
+
+ final View redSquare = mActivity.findViewById(R.id.redSquare);
+ final Rect newClip = new Rect(redSquare.getLeft() + 10, redSquare.getTop() + 10,
+ redSquare.getRight() - 10, redSquare.getBottom() - 10);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertNull(redSquare.getClipBounds());
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeClipBounds);
+ redSquare.setClipBounds(newClip);
+ }
+ });
+ waitForStart();
+ Thread.sleep(150);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Rect midClip = redSquare.getClipBounds();
+ assertNotNull(midClip);
+ assertTrue(midClip.left > 0 && midClip.left < newClip.left);
+ assertTrue(midClip.top > 0 && midClip.top < newClip.top);
+ assertTrue(midClip.right < redSquare.getRight() && midClip.right > newClip.right);
+ assertTrue(midClip.bottom < redSquare.getBottom() &&
+ midClip.bottom > newClip.bottom);
+ }
+ });
+ waitForEnd(400);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final Rect endRect = redSquare.getClipBounds();
+ assertNotNull(endRect);
+ assertEquals(newClip, endRect);
+ }
+ });
+
+ resetListener();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeClipBounds);
+ redSquare.setClipBounds(null);
+ }
+ });
+ waitForStart();
+ Thread.sleep(150);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Rect midClip = redSquare.getClipBounds();
+ assertNotNull(midClip);
+ assertTrue(midClip.left > 0 && midClip.left < newClip.left);
+ assertTrue(midClip.top > 0 && midClip.top < newClip.top);
+ assertTrue(midClip.right < redSquare.getRight() && midClip.right > newClip.right);
+ assertTrue(midClip.bottom < redSquare.getBottom() &&
+ midClip.bottom > newClip.bottom);
+ }
+ });
+ waitForEnd(400);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertNotNull(redSquare.getClipBounds());
+ }
+ });
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java b/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java
new file mode 100644
index 0000000..a26e850
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java
@@ -0,0 +1,286 @@
+/*
+ * 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.transition.cts;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.graphics.Matrix;
+import android.graphics.drawable.Drawable;
+import android.transition.ChangeImageTransform;
+import android.transition.TransitionManager;
+import android.transition.TransitionValues;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+
+public class ChangeImageTransformTest extends BaseTransitionTest {
+ ChangeImageTransform mChangeImageTransform;
+ Matrix mStartMatrix;
+ Matrix mEndMatrix;
+ Drawable mImage;
+ ImageView mImageView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ resetTransition();
+ mStartMatrix = null;
+ mEndMatrix = null;
+ mImage = null;
+ mImageView = null;
+ }
+
+ private void resetTransition() {
+ mChangeImageTransform = new CaptureMatrix();
+ mChangeImageTransform.setDuration(100);
+ mTransition = mChangeImageTransform;
+ resetListener();
+ }
+
+ public void testCenterToFitXY() throws Throwable {
+ transformImage(ScaleType.CENTER, ScaleType.FIT_XY);
+ assertMatrixMatches(centerMatrix(), mStartMatrix);
+ assertMatrixMatches(fitXYMatrix(), mEndMatrix);
+ }
+
+ public void testCenterCropToFitCenter() throws Throwable {
+ transformImage(ScaleType.CENTER_CROP, ScaleType.FIT_CENTER);
+ assertMatrixMatches(centerCropMatrix(), mStartMatrix);
+ assertMatrixMatches(fitCenterMatrix(), mEndMatrix);
+ }
+
+ public void testCenterInsideToFitEnd() throws Throwable {
+ transformImage(ScaleType.CENTER_INSIDE, ScaleType.FIT_END);
+ // CENTER_INSIDE and CENTER are the same when the image is smaller than the View
+ assertMatrixMatches(centerMatrix(), mStartMatrix);
+ assertMatrixMatches(fitEndMatrix(), mEndMatrix);
+ }
+
+ public void testFitStartToCenter() throws Throwable {
+ transformImage(ScaleType.FIT_START, ScaleType.CENTER);
+ assertMatrixMatches(fitStartMatrix(), mStartMatrix);
+ assertMatrixMatches(centerMatrix(), mEndMatrix);
+ }
+
+ private Matrix centerMatrix() {
+ int imageWidth = mImage.getIntrinsicWidth();
+ int imageViewWidth = mImageView.getWidth();
+ float tx = Math.round((imageViewWidth - imageWidth)/2f);
+
+ int imageHeight = mImage.getIntrinsicHeight();
+ int imageViewHeight = mImageView.getHeight();
+ float ty = Math.round((imageViewHeight - imageHeight)/2f);
+
+ Matrix matrix = new Matrix();
+ matrix.postTranslate(tx, ty);
+ return matrix;
+ }
+
+ private Matrix fitXYMatrix() {
+ int imageWidth = mImage.getIntrinsicWidth();
+ int imageViewWidth = mImageView.getWidth();
+ float scaleX = ((float)imageViewWidth)/imageWidth;
+
+ int imageHeight = mImage.getIntrinsicHeight();
+ int imageViewHeight = mImageView.getHeight();
+ float scaleY = ((float)imageViewHeight)/imageHeight;
+
+ Matrix matrix = new Matrix();
+ matrix.postScale(scaleX, scaleY);
+ return matrix;
+ }
+
+ private Matrix centerCropMatrix() {
+ int imageWidth = mImage.getIntrinsicWidth();
+ int imageViewWidth = mImageView.getWidth();
+ float scaleX = ((float)imageViewWidth)/imageWidth;
+
+ int imageHeight = mImage.getIntrinsicHeight();
+ int imageViewHeight = mImageView.getHeight();
+ float scaleY = ((float)imageViewHeight)/imageHeight;
+
+ float maxScale = Math.max(scaleX, scaleY);
+
+ float width = imageWidth * maxScale;
+ float height = imageHeight * maxScale;
+ float tx = Math.round((imageViewWidth - width) / 2f);
+ float ty = Math.round((imageViewHeight - height) / 2f);
+
+ Matrix matrix = new Matrix();
+ matrix.postScale(maxScale, maxScale);
+ matrix.postTranslate(tx, ty);
+ return matrix;
+ }
+
+ private Matrix fitCenterMatrix() {
+ int imageWidth = mImage.getIntrinsicWidth();
+ int imageViewWidth = mImageView.getWidth();
+ float scaleX = ((float)imageViewWidth)/imageWidth;
+
+ int imageHeight = mImage.getIntrinsicHeight();
+ int imageViewHeight = mImageView.getHeight();
+ float scaleY = ((float)imageViewHeight)/imageHeight;
+
+ float minScale = Math.min(scaleX, scaleY);
+
+ float width = imageWidth * minScale;
+ float height = imageHeight * minScale;
+ float tx = (imageViewWidth - width) / 2f;
+ float ty = (imageViewHeight - height) / 2f;
+
+ Matrix matrix = new Matrix();
+ matrix.postScale(minScale, minScale);
+ matrix.postTranslate(tx, ty);
+ return matrix;
+ }
+
+ private Matrix fitStartMatrix() {
+ int imageWidth = mImage.getIntrinsicWidth();
+ int imageViewWidth = mImageView.getWidth();
+ float scaleX = ((float)imageViewWidth)/imageWidth;
+
+ int imageHeight = mImage.getIntrinsicHeight();
+ int imageViewHeight = mImageView.getHeight();
+ float scaleY = ((float)imageViewHeight)/imageHeight;
+
+ float minScale = Math.min(scaleX, scaleY);
+
+ Matrix matrix = new Matrix();
+ matrix.postScale(minScale, minScale);
+ return matrix;
+ }
+
+ private Matrix fitEndMatrix() {
+ int imageWidth = mImage.getIntrinsicWidth();
+ int imageViewWidth = mImageView.getWidth();
+ float scaleX = ((float)imageViewWidth)/imageWidth;
+
+ int imageHeight = mImage.getIntrinsicHeight();
+ int imageViewHeight = mImageView.getHeight();
+ float scaleY = ((float)imageViewHeight)/imageHeight;
+
+ float minScale = Math.min(scaleX, scaleY);
+
+ float width = imageWidth * minScale;
+ float height = imageHeight * minScale;
+ float tx = imageViewWidth - width;
+ float ty = imageViewHeight - height;
+
+ Matrix matrix = new Matrix();
+ matrix.postScale(minScale, minScale);
+ matrix.postTranslate(tx, ty);
+ return matrix;
+ }
+
+ private void assertMatrixMatches(Matrix expected, Matrix matrix) {
+ if (expected == null) {
+ assertNull(matrix);
+ return;
+ }
+ assertNotNull(matrix);
+ float[] expectedValues = new float[9];
+ expected.getValues(expectedValues);
+
+ float[] values = new float[9];
+ matrix.getValues(values);
+
+ for (int i = 0; i < values.length; i++) {
+ final float expectedValue = expectedValues[i];
+ final float value = values[i];
+ assertEquals("Value [" + i + "]", expectedValue, value, 0.01f);
+ }
+ }
+
+ private void transformImage(ScaleType startScale, final ScaleType endScale) throws Throwable {
+ final ImageView imageView = enterImageViewScene(startScale);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeImageTransform);
+ imageView.setScaleType(endScale);
+ }
+ });
+ waitForStart();
+ int expectedEndCount = (startScale == endScale) ? 0 : 1;
+ assertEquals(expectedEndCount, mListener.endLatch.getCount());
+ waitForEnd(200);
+ }
+
+ private ImageView enterImageViewScene(final ScaleType scaleType) throws Throwable {
+ enterScene(R.layout.scene4);
+ final ViewGroup container = (ViewGroup) mActivity.findViewById(R.id.holder);
+ final ImageView[] imageViews = new ImageView[1];
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mImageView = new ImageView(mActivity);
+ mImage = mActivity.getDrawable(android.R.drawable.ic_media_play);
+ mImageView.setImageDrawable(mImage);
+ mImageView.setScaleType(scaleType);
+ imageViews[0] = mImageView;
+ container.addView(mImageView);
+ LayoutParams layoutParams = mImageView.getLayoutParams();
+ DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
+ float size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, metrics);
+ layoutParams.width = Math.round(size);
+ layoutParams.height = Math.round(size * 2);
+ mImageView.setLayoutParams(layoutParams);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ return imageViews[0];
+ }
+
+ private class CaptureMatrix extends ChangeImageTransform {
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
+ animator.addListener(new CaptureMatrixListener((ImageView) endValues.view));
+ return animator;
+ }
+ }
+
+ private class CaptureMatrixListener extends AnimatorListenerAdapter {
+ private final ImageView mImageView;
+
+ public CaptureMatrixListener(ImageView view) {
+ mImageView = view;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mStartMatrix = copyMatrix();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mEndMatrix = copyMatrix();
+ }
+
+ private Matrix copyMatrix() {
+ Matrix matrix = mImageView.getImageMatrix();
+ if (matrix != null) {
+ matrix = new Matrix(matrix);
+ }
+ return matrix;
+ }
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java b/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
index 9917416..2dee364 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
@@ -15,38 +15,38 @@
*/
package android.transition.cts;
-import android.transition.cts.R;
-
import android.transition.ChangeScroll;
-import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.View;
public class ChangeScrollTest extends BaseTransitionTest {
+ ChangeScroll mChangeScroll;
public ChangeScrollTest() {
}
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mChangeScroll = new ChangeScroll();
+ mTransition = mChangeScroll;
+ resetListener();
+ }
+
public void testChangeScroll() throws Throwable {
enterScene(R.layout.scene5);
- final Transition transition = new ChangeScroll();
- transition.setDuration(200);
- SimpleTransitionListener listener = new SimpleTransitionListener();
- transition.addListener(listener);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
final View view = mActivity.findViewById(R.id.text);
- final int scrollX = view.getScrollX();
- final int scrollY = view.getScrollY();
- assertEquals(0, scrollX);
- assertEquals(0, scrollY);
- TransitionManager.beginDelayedTransition(mSceneRoot, transition);
+ assertEquals(0, view.getScrollX());
+ assertEquals(0, view.getScrollY());
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeScroll);
view.scrollTo(150, 300);
}
});
- waitForStart(listener);
- waitForAnimationFrame();
+ waitForStart();
+ Thread.sleep(150);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
@@ -59,15 +59,13 @@
assertTrue(scrollY < 300);
}
});
- waitForEnd(listener, 250);
+ waitForEnd(400);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
final View view = mActivity.findViewById(R.id.text);
- final int scrollX = view.getScrollX();
- final int scrollY = view.getScrollY();
- assertEquals(150, scrollX);
- assertEquals(300, scrollY);
+ assertEquals(150, view.getScrollX());
+ assertEquals(300, view.getScrollY());
}
});
}
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java b/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java
new file mode 100644
index 0000000..78a5d82
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.transition.cts;
+
+import android.transition.ChangeTransform;
+import android.transition.TransitionManager;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ChangeTransformTest extends BaseTransitionTest {
+ ChangeTransform mChangeTransform;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ resetChangeBoundsTransition();
+ }
+
+ private void resetChangeBoundsTransition() {
+ mChangeTransform = new ChangeTransform();
+ mTransition = mChangeTransform;
+ resetListener();
+ }
+
+ public void testTranslation() throws Throwable {
+ enterScene(R.layout.scene1);
+
+ final View redSquare = mActivity.findViewById(R.id.redSquare);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
+ redSquare.setTranslationX(500);
+ redSquare.setTranslationY(600);
+ }
+ });
+ waitForStart();
+
+ assertEquals(1, mListener.endLatch.getCount()); // still running
+ // There is no way to validate the intermediate matrix because it uses
+ // hidden properties of the View to execute.
+ waitForEnd(400);
+ assertEquals(500f, redSquare.getTranslationX());
+ assertEquals(600f, redSquare.getTranslationY());
+ }
+
+ public void testRotation() throws Throwable {
+ enterScene(R.layout.scene1);
+
+ final View redSquare = mActivity.findViewById(R.id.redSquare);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
+ redSquare.setRotation(45);
+ }
+ });
+ waitForStart();
+
+ assertEquals(1, mListener.endLatch.getCount()); // still running
+ // There is no way to validate the intermediate matrix because it uses
+ // hidden properties of the View to execute.
+ waitForEnd(400);
+ assertEquals(45f, redSquare.getRotation());
+ }
+
+ public void testScale() throws Throwable {
+ enterScene(R.layout.scene1);
+
+ final View redSquare = mActivity.findViewById(R.id.redSquare);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
+ redSquare.setScaleX(2f);
+ redSquare.setScaleY(3f);
+ }
+ });
+ waitForStart();
+
+ assertEquals(1, mListener.endLatch.getCount()); // still running
+ // There is no way to validate the intermediate matrix because it uses
+ // hidden properties of the View to execute.
+ waitForEnd(400);
+ assertEquals(2f, redSquare.getScaleX());
+ assertEquals(3f, redSquare.getScaleY());
+ }
+
+ public void testReparent() throws Throwable {
+ assertEquals(true, mChangeTransform.getReparent());
+ enterScene(R.layout.scene5);
+ startTransition(R.layout.scene9);
+ assertEquals(1, mListener.endLatch.getCount()); // still running
+ waitForEnd(400);
+
+ resetListener();
+ mChangeTransform.setReparent(false);
+ assertEquals(false, mChangeTransform.getReparent());
+ startTransition(R.layout.scene5);
+ waitForEnd(0); // no transition to run because reparent == false
+ }
+
+ public void testReparentWithOverlay() throws Throwable {
+ assertEquals(true, mChangeTransform.getReparentWithOverlay());
+ enterScene(R.layout.scene5);
+ startTransition(R.layout.scene9);
+ assertEquals(1, mListener.endLatch.getCount()); // still running
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View view = new View(mActivity);
+ view.setRight(100);
+ view.setBottom(100);
+ mSceneRoot.getOverlay().add(view);
+ ViewGroup container = (ViewGroup) view.getParent();
+ assertEquals(2, container.getChildCount());
+ mSceneRoot.getOverlay().remove(view);
+ assertTrue(mActivity.findViewById(R.id.text).getVisibility() != View.VISIBLE);
+ }
+ });
+ waitForEnd(400);
+
+ mChangeTransform.setReparentWithOverlay(false);
+ assertEquals(false, mChangeTransform.getReparentWithOverlay());
+ resetListener();
+ startTransition(R.layout.scene5);
+ assertEquals(1, mListener.endLatch.getCount()); // still running
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View view = new View(mActivity);
+ view.setRight(100);
+ view.setBottom(100);
+ mSceneRoot.getOverlay().add(view);
+ ViewGroup container = (ViewGroup) view.getParent();
+ assertEquals(1, container.getChildCount());
+ mSceneRoot.getOverlay().remove(view);
+ assertEquals(View.VISIBLE, mActivity.findViewById(R.id.text).getVisibility());
+ }
+ });
+ waitForEnd(400);
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
new file mode 100644
index 0000000..e9e2264
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.transition.cts;
+
+import android.transition.Explode;
+import android.transition.TransitionManager;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.RelativeLayout.LayoutParams;
+
+public class ExplodeTest extends BaseTransitionTest {
+ Explode mExplode;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ resetTransition();
+ }
+
+ private void resetTransition() {
+ mExplode = new Explode();
+ mTransition = mExplode;
+ resetListener();
+ }
+
+ public void testExplode() throws Throwable {
+ enterScene(R.layout.scene10);
+ final View redSquare = mActivity.findViewById(R.id.redSquare);
+ final View greenSquare = mActivity.findViewById(R.id.greenSquare);
+ final View blueSquare = mActivity.findViewById(R.id.blueSquare);
+ final View yellowSquare = mActivity.findViewById(R.id.yellowSquare);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+ redSquare.setVisibility(View.INVISIBLE);
+ greenSquare.setVisibility(View.INVISIBLE);
+ blueSquare.setVisibility(View.INVISIBLE);
+ yellowSquare.setVisibility(View.INVISIBLE);
+ }
+ });
+ waitForStart();
+ assertEquals(1, mListener.endLatch.getCount());
+ assertEquals(View.VISIBLE, redSquare.getVisibility());
+ assertEquals(View.VISIBLE, greenSquare.getVisibility());
+ assertEquals(View.VISIBLE, blueSquare.getVisibility());
+ assertEquals(View.VISIBLE, yellowSquare.getVisibility());
+ float redStartX = redSquare.getTranslationX();
+ float redStartY = redSquare.getTranslationY();
+
+ Thread.sleep(100);
+ assertTranslation(redSquare, true, true);
+ assertTranslation(greenSquare, false, true);
+ assertTranslation(blueSquare, false, false);
+ assertTranslation(yellowSquare, true, false);
+ assertTrue(redStartX > redSquare.getTranslationX()); // moving left
+ assertTrue(redStartY > redSquare.getTranslationY()); // moving up
+ waitForEnd(400);
+
+ assertNoTranslation(redSquare);
+ assertNoTranslation(greenSquare);
+ assertNoTranslation(blueSquare);
+ assertNoTranslation(yellowSquare);
+ assertEquals(View.INVISIBLE, redSquare.getVisibility());
+ assertEquals(View.INVISIBLE, greenSquare.getVisibility());
+ assertEquals(View.INVISIBLE, blueSquare.getVisibility());
+ assertEquals(View.INVISIBLE, yellowSquare.getVisibility());
+ }
+
+ public void testImplode() throws Throwable {
+ enterScene(R.layout.scene10);
+ final View redSquare = mActivity.findViewById(R.id.redSquare);
+ final View greenSquare = mActivity.findViewById(R.id.greenSquare);
+ final View blueSquare = mActivity.findViewById(R.id.blueSquare);
+ final View yellowSquare = mActivity.findViewById(R.id.yellowSquare);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ redSquare.setVisibility(View.INVISIBLE);
+ greenSquare.setVisibility(View.INVISIBLE);
+ blueSquare.setVisibility(View.INVISIBLE);
+ yellowSquare.setVisibility(View.INVISIBLE);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+ redSquare.setVisibility(View.VISIBLE);
+ greenSquare.setVisibility(View.VISIBLE);
+ blueSquare.setVisibility(View.VISIBLE);
+ yellowSquare.setVisibility(View.VISIBLE);
+ }
+ });
+ waitForStart();
+
+ assertEquals(View.VISIBLE, redSquare.getVisibility());
+ assertEquals(View.VISIBLE, greenSquare.getVisibility());
+ assertEquals(View.VISIBLE, blueSquare.getVisibility());
+ assertEquals(View.VISIBLE, yellowSquare.getVisibility());
+ float redStartX = redSquare.getTranslationX();
+ float redStartY = redSquare.getTranslationY();
+
+ Thread.sleep(100);
+ assertTranslation(redSquare, true, true);
+ assertTranslation(greenSquare, false, true);
+ assertTranslation(blueSquare, false, false);
+ assertTranslation(yellowSquare, true, false);
+ assertTrue(redStartX < redSquare.getTranslationX()); // moving right
+ assertTrue(redStartY < redSquare.getTranslationY()); // moving down
+ waitForEnd(400);
+
+ assertNoTranslation(redSquare);
+ assertNoTranslation(greenSquare);
+ assertNoTranslation(blueSquare);
+ assertNoTranslation(yellowSquare);
+ assertEquals(View.VISIBLE, redSquare.getVisibility());
+ assertEquals(View.VISIBLE, greenSquare.getVisibility());
+ assertEquals(View.VISIBLE, blueSquare.getVisibility());
+ assertEquals(View.VISIBLE, yellowSquare.getVisibility());
+ }
+
+ private void assertTranslation(View view, boolean goLeft, boolean goUp) {
+ float translationX = view.getTranslationX();
+ float translationY = view.getTranslationY();
+
+ if (goLeft) {
+ assertTrue(translationX < 0);
+ } else {
+ assertTrue(translationX > 0);
+ }
+
+ if (goUp) {
+ assertTrue(translationY < 0);
+ } else {
+ assertTrue(translationY > 0);
+ }
+ }
+
+ private void assertNoTranslation(View view) {
+ assertEquals(0f, view.getTranslationX());
+ assertEquals(0f, view.getTranslationY());
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/FadeTest.java b/tests/tests/transition/src/android/transition/cts/FadeTest.java
new file mode 100644
index 0000000..a6a1b2f
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/FadeTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.transition.cts;
+
+import android.transition.Fade;
+
+/**
+ * This tests the public API for Fade. The alpha cannot be easily tested as part of CTS,
+ * so those are implementation tests.
+ */
+public class FadeTest extends BaseTransitionTest {
+ Fade mFade;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ resetTransition();
+ }
+
+ private void resetTransition() {
+ mFade = new Fade();
+ mFade.setDuration(200);
+ mTransition = mFade;
+ resetListener();
+ }
+
+ public void testMode() throws Throwable {
+ // Should animate in and out by default
+ enterScene(R.layout.scene4);
+ startTransition(R.layout.scene1);
+ assertEquals(1, mListener.endLatch.getCount());
+ waitForEnd(400);
+
+ resetListener();
+ startTransition(R.layout.scene4);
+ assertEquals(1, mListener.endLatch.getCount());
+ waitForEnd(400);
+
+ // Now only animate in
+ mFade = new Fade(Fade.IN);
+ mTransition = mFade;
+ resetListener();
+ startTransition(R.layout.scene1);
+ assertEquals(1, mListener.endLatch.getCount());
+ waitForEnd(400);
+
+ // No animation since it should only animate in
+ resetListener();
+ startTransition(R.layout.scene4);
+ waitForEnd(0);
+
+ // Now animate out, but no animation should happen since we're animating in.
+ mFade = new Fade(Fade.OUT);
+ mTransition = mFade;
+ resetListener();
+ startTransition(R.layout.scene1);
+ waitForEnd(0);
+
+ // but it should animate out
+ resetListener();
+ startTransition(R.layout.scene4);
+ assertEquals(1, mListener.endLatch.getCount());
+ waitForEnd(400);
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/PathMotionTest.java b/tests/tests/transition/src/android/transition/cts/PathMotionTest.java
new file mode 100644
index 0000000..97bf274
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/PathMotionTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.transition.cts;
+
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+
+import junit.framework.TestCase;
+
+public class PathMotionTest extends TestCase {
+ public static void assertPathMatches(Path expectedPath, Path path) {
+ PathMeasure expectedMeasure = new PathMeasure(expectedPath, false);
+ PathMeasure pathMeasure = new PathMeasure(path, false);
+
+ float expectedLength = expectedMeasure.getLength();
+ assertEquals(expectedLength, pathMeasure.getLength(), 0.01f);
+
+ float minLength = Math.min(expectedLength, pathMeasure.getLength());
+
+ float pos[] = new float[2];
+
+ float increment = minLength / 5f;
+ for (float along = 0; along <= minLength; along += increment) {
+ expectedMeasure.getPosTan(along, pos, null);
+ float expectedX = pos[0];
+ float expectedY = pos[1];
+
+ pathMeasure.getPosTan(along, pos, null);
+ assertEquals(expectedX, pos[0], 0.01f);
+ assertEquals(expectedY, pos[1], 0.01f);
+ }
+ }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java b/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
new file mode 100644
index 0000000..5485b4a
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.transition.cts;
+
+import android.graphics.Path;
+import android.transition.PatternPathMotion;
+
+public class PatternPathMotionTest extends PathMotionTest {
+
+ public void testStraightPath() throws Throwable {
+ Path pattern = new Path();
+ pattern.moveTo(100, 500);
+ pattern.lineTo(300, 1000);
+
+ PatternPathMotion pathMotion = new PatternPathMotion(pattern);
+ assertPathMatches(pattern, pathMotion.getPatternPath());
+
+ Path expected = new Path();
+ expected.moveTo(0, 0);
+ expected.lineTo(100, 100);
+
+ assertPathMatches(expected, pathMotion.getPath(0, 0, 100, 100));
+ }
+
+ public void testCurve() throws Throwable {
+ Path pattern = new Path();
+ pattern.addArc(0, 0, 100, 100, 0, 180);
+
+ PatternPathMotion pathMotion = new PatternPathMotion(pattern);
+ assertPathMatches(pattern, pathMotion.getPatternPath());
+
+ Path expected = new Path();
+ expected.addArc(-50, 0, 50, 100, -90, 180);
+
+ assertPathMatches(expected, pathMotion.getPath(0, 0, 0, 100));
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java
new file mode 100644
index 0000000..fefa353
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.transition.cts;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.transition.Slide;
+import android.view.Gravity;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+public class SlideBadEdgeTest extends TestCase {
+
+ private static final Object[][] sBadGravity = {
+ { Gravity.AXIS_CLIP, "AXIS_CLIP" },
+ { Gravity.AXIS_PULL_AFTER, "AXIS_PULL_AFTER" },
+ { Gravity.AXIS_PULL_BEFORE, "AXIS_PULL_BEFORE" },
+ { Gravity.AXIS_SPECIFIED, "AXIS_SPECIFIED" },
+ { Gravity.AXIS_Y_SHIFT, "AXIS_Y_SHIFT" },
+ { Gravity.AXIS_X_SHIFT, "AXIS_X_SHIFT" },
+ { Gravity.CENTER, "CENTER" },
+ { Gravity.CLIP_VERTICAL, "CLIP_VERTICAL" },
+ { Gravity.CLIP_HORIZONTAL, "CLIP_HORIZONTAL" },
+ { Gravity.CENTER_VERTICAL, "CENTER_VERTICAL" },
+ { Gravity.CENTER_HORIZONTAL, "CENTER_HORIZONTAL" },
+ { Gravity.DISPLAY_CLIP_VERTICAL, "DISPLAY_CLIP_VERTICAL" },
+ { Gravity.DISPLAY_CLIP_HORIZONTAL, "DISPLAY_CLIP_HORIZONTAL" },
+ { Gravity.FILL_VERTICAL, "FILL_VERTICAL" },
+ { Gravity.FILL, "FILL" },
+ { Gravity.FILL_HORIZONTAL, "FILL_HORIZONTAL" },
+ { Gravity.HORIZONTAL_GRAVITY_MASK, "HORIZONTAL_GRAVITY_MASK" },
+ { Gravity.NO_GRAVITY, "NO_GRAVITY" },
+ { Gravity.RELATIVE_LAYOUT_DIRECTION, "RELATIVE_LAYOUT_DIRECTION" },
+ { Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK, "RELATIVE_HORIZONTAL_GRAVITY_MASK" },
+ { Gravity.VERTICAL_GRAVITY_MASK, "VERTICAL_GRAVITY_MASK" },
+ };
+
+ @SmallTest
+ public void testBadSide() {
+ for (int i = 0; i < sBadGravity.length; i++) {
+ int badEdge = (Integer) sBadGravity[i][0];
+ String edgeName = (String) sBadGravity[i][1];
+ try {
+ Slide slide = new Slide(badEdge);
+ fail("Should not be able to set slide edge to " + edgeName);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ Slide slide = new Slide();
+ slide.setSlideEdge(badEdge);
+ fail("Should not be able to set slide edge to " + edgeName);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java
new file mode 100644
index 0000000..060b4cc
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.transition.cts;
+
+import android.support.test.rule.ActivityTestRule;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.transition.Slide;
+import android.transition.TransitionManager;
+import android.view.Gravity;
+import android.view.View;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class SlideDefaultEdgeTest {
+ @Test
+ @SmallTest
+ public void testDefaultSide() {
+ // default to bottom
+ Slide slide = new Slide();
+ assertEquals(Gravity.BOTTOM, slide.getSlideEdge());
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
new file mode 100644
index 0000000..01225dc
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
@@ -0,0 +1,269 @@
+/*
+ * 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.transition.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.transition.Slide;
+import android.transition.TransitionManager;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+public class SlideEdgeTest extends ActivityInstrumentationTestCase2<TransitionActivity> {
+ private static final Object[][] sSlideEdgeArray = {
+ { Gravity.START, "START" },
+ { Gravity.END, "END" },
+ { Gravity.LEFT, "LEFT" },
+ { Gravity.TOP, "TOP" },
+ { Gravity.RIGHT, "RIGHT" },
+ { Gravity.BOTTOM, "BOTTOM" },
+ };
+
+ public SlideEdgeTest() {
+ super(TransitionActivity.class);
+ }
+
+ public void testSetSide() throws Throwable {
+ for (int i = 0; i < sSlideEdgeArray.length; i++) {
+ int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
+ String edgeName = (String) (sSlideEdgeArray[i][1]);
+ Slide slide = new Slide(slideEdge);
+ assertEquals("Edge not set properly in constructor " + edgeName,
+ slideEdge, slide.getSlideEdge());
+
+ slide = new Slide();
+ slide.setSlideEdge(slideEdge);
+ assertEquals("Edge not set properly with setter " + edgeName,
+ slideEdge, slide.getSlideEdge());
+ }
+ }
+
+ public void testSlideOut() throws Throwable {
+ for (int i = 0; i < sSlideEdgeArray.length; i++) {
+ final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
+ final Slide slide = new Slide(slideEdge);
+ final SimpleTransitionListener listener = new SimpleTransitionListener();
+ slide.addListener(listener);
+
+ final Instrumentation instrumentation = getInstrumentation();
+ final Activity activity = getActivity();
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ activity.setContentView(R.layout.scene1);
+ }
+ });
+ instrumentation.waitForIdleSync();
+
+ final View redSquare = activity.findViewById(R.id.redSquare);
+ final View greenSquare = activity.findViewById(R.id.greenSquare);
+ final View hello = activity.findViewById(R.id.hello);
+ final ViewGroup sceneRoot = (ViewGroup) activity.findViewById(R.id.holder);
+
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(sceneRoot, slide);
+ redSquare.setVisibility(View.INVISIBLE);
+ greenSquare.setVisibility(View.INVISIBLE);
+ hello.setVisibility(View.INVISIBLE);
+ }
+ });
+ assertTrue(listener.startLatch.await(1, TimeUnit.SECONDS));
+ assertEquals(1, listener.endLatch.getCount());
+ assertEquals(View.VISIBLE, redSquare.getVisibility());
+ assertEquals(View.VISIBLE, greenSquare.getVisibility());
+ assertEquals(View.VISIBLE, hello.getVisibility());
+
+ float redStartX = redSquare.getTranslationX();
+ float redStartY = redSquare.getTranslationY();
+
+ Thread.sleep(200);
+ assertTranslation(slideEdge, redSquare);
+ assertTranslation(slideEdge, greenSquare);
+ assertTranslation(slideEdge, hello);
+
+ final float redMidX = redSquare.getTranslationX();
+ final float redMidY = redSquare.getTranslationY();
+
+ switch (slideEdge) {
+ case Gravity.LEFT:
+ case Gravity.START:
+ assertTrue(
+ "isn't sliding out to left. Expecting " + redStartX + " > " + redMidX,
+ redStartX > redMidX);
+ break;
+ case Gravity.RIGHT:
+ case Gravity.END:
+ assertTrue(
+ "isn't sliding out to right. Expecting " + redStartX + " < " + redMidX,
+ redStartX < redMidX);
+ break;
+ case Gravity.TOP:
+ assertTrue("isn't sliding out to top. Expecting " + redStartY + " > " + redMidY,
+ redStartY > redSquare.getTranslationY());
+ break;
+ case Gravity.BOTTOM:
+ assertTrue(
+ "isn't sliding out to bottom. Expecting " + redStartY + " < " + redMidY,
+ redStartY < redSquare.getTranslationY());
+ break;
+ }
+ assertTrue(listener.endLatch.await(1, TimeUnit.SECONDS));
+ instrumentation.waitForIdleSync();
+
+ assertNoTranslation(redSquare);
+ assertNoTranslation(greenSquare);
+ assertNoTranslation(hello);
+ assertEquals(View.INVISIBLE, redSquare.getVisibility());
+ assertEquals(View.INVISIBLE, greenSquare.getVisibility());
+ assertEquals(View.INVISIBLE, hello.getVisibility());
+ }
+ }
+
+ public void testSlideIn() throws Throwable {
+ for (int i = 0; i < sSlideEdgeArray.length; i++) {
+ final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
+ final Slide slide = new Slide(slideEdge);
+ final SimpleTransitionListener listener = new SimpleTransitionListener();
+ slide.addListener(listener);
+
+ final Instrumentation instrumentation = getInstrumentation();
+ final Activity activity = getActivity();
+
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ activity.setContentView(R.layout.scene1);
+ }
+ });
+ instrumentation.waitForIdleSync();
+
+ final View redSquare = activity.findViewById(R.id.redSquare);
+ final View greenSquare = activity.findViewById(R.id.greenSquare);
+ final View hello = activity.findViewById(R.id.hello);
+ final ViewGroup sceneRoot = (ViewGroup) activity.findViewById(R.id.holder);
+
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ redSquare.setVisibility(View.INVISIBLE);
+ greenSquare.setVisibility(View.INVISIBLE);
+ hello.setVisibility(View.INVISIBLE);
+ }
+ });
+ instrumentation.waitForIdleSync();
+
+ // now slide in
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(sceneRoot, slide);
+ redSquare.setVisibility(View.VISIBLE);
+ greenSquare.setVisibility(View.VISIBLE);
+ hello.setVisibility(View.VISIBLE);
+ }
+ });
+ assertTrue(listener.startLatch.await(1, TimeUnit.SECONDS));
+
+ assertEquals(1, listener.endLatch.getCount());
+ assertEquals(View.VISIBLE, redSquare.getVisibility());
+ assertEquals(View.VISIBLE, greenSquare.getVisibility());
+ assertEquals(View.VISIBLE, hello.getVisibility());
+
+ final float redStartX = redSquare.getTranslationX();
+ final float redStartY = redSquare.getTranslationY();
+
+ Thread.sleep(200);
+ assertTranslation(slideEdge, redSquare);
+ assertTranslation(slideEdge, greenSquare);
+ assertTranslation(slideEdge, hello);
+ final float redMidX = redSquare.getTranslationX();
+ final float redMidY = redSquare.getTranslationY();
+
+ switch (slideEdge) {
+ case Gravity.LEFT:
+ case Gravity.START:
+ assertTrue(
+ "isn't sliding in from left. Expecting " + redStartX + " < " + redMidX,
+ redStartX < redMidX);
+ break;
+ case Gravity.RIGHT:
+ case Gravity.END:
+ assertTrue(
+ "isn't sliding in from right. Expecting " + redStartX + " > " + redMidX,
+ redStartX > redMidX);
+ break;
+ case Gravity.TOP:
+ assertTrue(
+ "isn't sliding in from top. Expecting " + redStartY + " < " + redMidY,
+ redStartY < redSquare.getTranslationY());
+ break;
+ case Gravity.BOTTOM:
+ assertTrue("isn't sliding in from bottom. Expecting " + redStartY + " > "
+ + redMidY,
+ redStartY > redSquare.getTranslationY());
+ break;
+ }
+ assertTrue(listener.endLatch.await(1, TimeUnit.SECONDS));
+ instrumentation.waitForIdleSync();
+
+ assertNoTranslation(redSquare);
+ assertNoTranslation(greenSquare);
+ assertNoTranslation(hello);
+ assertEquals(View.VISIBLE, redSquare.getVisibility());
+ assertEquals(View.VISIBLE, greenSquare.getVisibility());
+ assertEquals(View.VISIBLE, hello.getVisibility());
+ }
+ }
+
+ private void assertTranslation(int slideEdge, View view) {
+ switch (slideEdge) {
+ case Gravity.LEFT:
+ case Gravity.START:
+ assertTrue(view.getTranslationX() < 0);
+ assertEquals(0f, view.getTranslationY(), 0.01f);
+ break;
+ case Gravity.RIGHT:
+ case Gravity.END:
+ assertTrue(view.getTranslationX() > 0);
+ assertEquals(0f, view.getTranslationY(), 0.01f);
+ break;
+ case Gravity.TOP:
+ assertTrue(view.getTranslationY() < 0);
+ assertEquals(0f, view.getTranslationX(), 0.01f);
+ break;
+ case Gravity.BOTTOM:
+ assertTrue(view.getTranslationY() > 0);
+ assertEquals(0f, view.getTranslationX(), 0.01f);
+ break;
+ }
+ }
+
+ private void assertNoTranslation(View view) {
+ assertEquals(0f, view.getTranslationX(), 0.01f);
+ assertEquals(0f, view.getTranslationY(), 0.01f);
+ }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java b/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java
index 3afe812..adfc36a 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java
@@ -39,10 +39,13 @@
assertEquals(TransitionSet.ORDERING_TOGETHER, transitionSet.getOrdering());
enterScene(R.layout.scene1);
startTransition(R.layout.scene3);
- assertTrue(fadeListener.startLatch.await(0, TimeUnit.MILLISECONDS));
- assertTrue(changeBoundsListener.startLatch.await(0, TimeUnit.MILLISECONDS));
-
- endTransition();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals(0, fadeListener.startLatch.getCount());
+ assertEquals(0, changeBoundsListener.startLatch.getCount());
+ }
+ });
}
public void testTransitionSequentially() throws Throwable {
@@ -64,11 +67,20 @@
enterScene(R.layout.scene1);
startTransition(R.layout.scene3);
- assertTrue(fadeListener.startLatch.await(0, TimeUnit.MILLISECONDS));
- assertEquals(1, changeBoundsListener.startLatch.getCount());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals(0, fadeListener.startLatch.getCount());
+ assertEquals(1, changeBoundsListener.startLatch.getCount());
+ }
+ });
assertTrue(fadeListener.endLatch.await(400, TimeUnit.MILLISECONDS));
- assertTrue(changeBoundsListener.startLatch.await(0, TimeUnit.MILLISECONDS));
- endTransition();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals(0, changeBoundsListener.startLatch.getCount());
+ }
+ });
}
public void testTransitionCount() throws Throwable {
diff --git a/tests/tests/transition/src/android/transition/cts/VisibilityTest.java b/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
index 091b229..9b91a36 100644
--- a/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
+++ b/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
@@ -15,15 +15,9 @@
*/
package android.transition.cts;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.transition.TransitionValues;
import android.transition.Visibility;
import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
public class VisibilityTest extends BaseTransitionTest {
Visibility mVisibilityTransition;
@@ -41,20 +35,31 @@
assertEquals(Visibility.MODE_IN | Visibility.MODE_OUT, mVisibilityTransition.getMode());
// Should animate in and out
+ enterScene(R.layout.scene4);
+ startTransition(R.layout.scene1);
+ assertEquals(1, mListener.endLatch.getCount());
+ waitForEnd(400);
+
+ resetListener();
startTransition(R.layout.scene4);
assertEquals(1, mListener.endLatch.getCount());
- endTransition();
- waitForEnd(100);
+ waitForEnd(400);
+ // Now only animate in
resetListener();
mVisibilityTransition.setMode(Visibility.MODE_IN);
startTransition(R.layout.scene1);
assertEquals(1, mListener.endLatch.getCount());
- endTransition();
- waitForEnd(100);
+ waitForEnd(400);
+ // No animation since it should only animate in
resetListener();
- mVisibilityTransition.setMode(Visibility.MODE_OUT); // now it shouldn't do any animation
+ startTransition(R.layout.scene4);
+ waitForEnd(0);
+
+ // Now animate out, but no animation should happen since we're animating in.
+ resetListener();
+ mVisibilityTransition.setMode(Visibility.MODE_OUT);
startTransition(R.layout.scene1);
waitForEnd(0);
@@ -62,20 +67,7 @@
resetListener();
startTransition(R.layout.scene4);
assertEquals(1, mListener.endLatch.getCount());
- endTransition();
- waitForEnd(100);
-
- // switch the mode to only animate in
- resetListener();
- mVisibilityTransition.setMode(Visibility.MODE_IN);
- startTransition(R.layout.scene1);
- assertEquals(1, mListener.endLatch.getCount());
- endTransition();
- waitForEnd(100);
-
- // but it shouldn't animate out
- startTransition(R.layout.scene1);
- waitForEnd(0);
+ waitForEnd(400);
}
public void testIsVisible() throws Throwable {
diff --git a/tests/tests/uiautomation/AndroidManifest.xml b/tests/tests/uiautomation/AndroidManifest.xml
index dac6532..6dc28ed 100644
--- a/tests/tests/uiautomation/AndroidManifest.xml
+++ b/tests/tests/uiautomation/AndroidManifest.xml
@@ -52,7 +52,7 @@
</application>
- <instrumentation android:name="android.support.test.uiautomator.UiAutomatorInstrumentationTestRunner"
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.app.uiautomation.cts">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/uiautomation/AndroidTest.xml b/tests/tests/uiautomation/AndroidTest.xml
index cf15c6b..c4f1665 100644
--- a/tests/tests/uiautomation/AndroidTest.xml
+++ b/tests/tests/uiautomation/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.app.uiautomation.cts" />
+ <option name="runtime-hint" value="6m42s" />
</test>
</configuration>
diff --git a/tests/tests/uirendering/AndroidTest.xml b/tests/tests/uirendering/AndroidTest.xml
index 30c99db..c89300b 100644
--- a/tests/tests/uirendering/AndroidTest.xml
+++ b/tests/tests/uirendering/AndroidTest.xml
@@ -20,6 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.uirendering.cts" />
- <option name="runtime-hint" value="3m" />
+ <option name="runtime-hint" value="11m55s" />
</test>
</configuration>
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 b324b06..d0820e2 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -20,13 +20,15 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.testinfrastructure.CanvasClient;
+import org.junit.Test;
+@MediumTest
public class BitmapFilterTests extends ActivityTestBase {
private static final int WHITE_WEIGHT = 255 * 3;
private enum FilterEnum {
@@ -75,32 +77,32 @@
private static final int BIG_GRID_SIZE = TEST_WIDTH * 2;
private Bitmap mBigGridBitmap = createGridBitmap(BIG_GRID_SIZE, BIG_GRID_SIZE);
- @SmallTest
+ @Test
public void testPaintFilterScaleUp() {
runScaleTest(FilterEnum.PAINT_FILTER, true);
}
- @SmallTest
+ @Test
public void testPaintFilterScaleDown() {
runScaleTest(FilterEnum.PAINT_FILTER, false);
}
- @SmallTest
+ @Test
public void testDrawFilterRemoveFilterScaleUp() {
runScaleTest(FilterEnum.REMOVE_FILTER, true);
}
- @SmallTest
+ @Test
public void testDrawFilterRemoveFilterScaleDown() {
runScaleTest(FilterEnum.REMOVE_FILTER, false);
}
- @SmallTest
+ @Test
public void testDrawFilterScaleUp() {
runScaleTest(FilterEnum.ADD_FILTER, true);
}
- @SmallTest
+ @Test
public void testDrawFilterScaleDown() {
runScaleTest(FilterEnum.ADD_FILTER, false);
}
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 becc2f7..38d884d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -20,9 +20,13 @@
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
-import android.test.suitebuilder.annotation.SmallTest;
+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;
+import static org.junit.Assert.assertTrue;
/**
* Tests of state query-able from canvas at draw time.
@@ -30,9 +34,9 @@
* Although these tests don't verify drawing content, they still make use of ActivityTestBase's
* capability to test the hardware accelerated Canvas in the way that it is used by Views.
*/
+@MediumTest
public class CanvasStateTests extends ActivityTestBase {
-
- @SmallTest
+ @Test
public void testClipRectReturnValues() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -50,7 +54,7 @@
.runWithoutVerification();
}
- @SmallTest
+ @Test
public void testClipRegionReturnValues() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -83,7 +87,7 @@
.runWithoutVerification();
}
- @SmallTest
+ @Test
public void testClipPathReturnValues() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -104,7 +108,7 @@
})
.runWithoutVerification();
}
- @SmallTest
+ @Test
public void testQuickReject() {
createTest()
.addCanvasClient(new CanvasClient() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
new file mode 100644
index 0000000..483ad87
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.uirendering.cts.testclasses;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.PorterDuffColorFilter;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.List;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class ColorFilterAlphaTest extends ActivityTestBase {
+ // We care about one point in each of the four rectangles of different alpha values, as well as
+ // the area outside the rectangles
+
+ public static final int FILTER_COLOR = 0xFFBB0000;
+
+ private static final Point[] TEST_POINTS = new Point[] {
+ new Point(9, 45),
+ new Point(27, 45),
+ new Point(45, 45),
+ new Point(63, 45),
+ new Point(81, 45)
+ };
+
+ private static Object[][] MODES_AND_EXPECTED_COLORS = new Object[][] {
+ { PorterDuff.Mode.DST, new int[] {
+ 0xFFE6E6E6, 0xFFCCCCCC, 0xFFB3B3B3, 0xFF999999, 0xFFFFFFFF } },
+
+ { PorterDuff.Mode.SRC_OVER, new int[] {
+ 0xFFBB0000, 0xFFBB0000, 0xFFBB0000, 0xFFBB0000, 0xFFBB0000 } },
+
+ { PorterDuff.Mode.DST_OVER, new int[] {
+ 0xFFAF1A1A, 0xFFA33333, 0xFF984D4D, 0xFF8B6666, 0xFFBB0000 } },
+
+ { PorterDuff.Mode.SRC_IN, new int[] {
+ 0xFFF1CCCC, 0xFFE49999, 0xFFD66666, 0xFFC83333, 0xFFFFFFFF } },
+
+ { PorterDuff.Mode.DST_IN, new int[] {
+ 0xFFE6E6E6, 0xFFCCCCCC, 0xFFB3B3B3, 0xFF999999, 0xFFFFFFFF } },
+
+ { PorterDuff.Mode.SRC_OUT, new int[] {
+ 0xFFC83333, 0xFFD66666, 0xFFE49999, 0xFFF1CCCC, 0xFFBB0000 } },
+
+ { PorterDuff.Mode.DST_OUT, new int[] {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } },
+
+ { PorterDuff.Mode.SRC_ATOP, new int[] {
+ 0xFFF1CCCC, 0xFFE49999, 0xFFD66666, 0xFFC93333, 0xFFFFFFFF } },
+
+ { PorterDuff.Mode.DST_ATOP, new int[] {
+ 0xFFB01A1A, 0xFFA33333, 0xFF984D4D, 0xFF8B6666, 0xFFBB0000 } },
+
+ { PorterDuff.Mode.XOR, new int[] {
+ 0xFFC93333, 0xFFD66666, 0xFFE49999, 0xFFF1CCCC, 0xFFBB0000 } },
+
+ { PorterDuff.Mode.MULTIPLY, new int[] {
+ 0xFFDFCCCC, 0xFFBE9999, 0xFF9E6666, 0xFF7E3333, 0xFFFFFFFF } },
+
+ { PorterDuff.Mode.SCREEN, new int[] {
+ 0xFFC21A1A, 0xFFC93333, 0xFFD04D4D, 0xFFD66666, 0xFFBB0000 } },
+ };
+
+ @Parameterized.Parameters(name = "{0}")
+ public static List<XfermodeTest.Config> configs() {
+ return XfermodeTest.configs(MODES_AND_EXPECTED_COLORS);
+ }
+
+ private final XfermodeTest.Config mConfig;
+
+ public ColorFilterAlphaTest(XfermodeTest.Config config) {
+ mConfig = config;
+ }
+
+ private static final int[] BLOCK_COLORS = new int[] {
+ 0x33808080,
+ 0x66808080,
+ 0x99808080,
+ 0xCC808080,
+ 0x00000000
+ };
+
+ private static Bitmap createMultiRectBitmap() {
+ Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint();
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ final int blockCount = BLOCK_COLORS.length;
+ final int blockWidth = TEST_WIDTH / blockCount;
+ for (int i = 0 ; i < blockCount; i++) {
+ paint.setColor(BLOCK_COLORS[i]);
+ canvas.drawRect(i * blockWidth, 0, (i + 1) * blockWidth, TEST_HEIGHT, paint);
+ }
+ return bitmap;
+ }
+
+ private CanvasClient mCanvasClient = new CanvasClient() {
+ final Paint mPaint = new Paint();
+ private final Bitmap mBitmap = createMultiRectBitmap();
+
+ @Override
+ public void draw(Canvas canvas, int width, int height) {
+ mPaint.setColorFilter(new PorterDuffColorFilter(FILTER_COLOR, mConfig.mode));
+ canvas.drawBitmap(mBitmap, 0, 0, mPaint);
+ }
+ };
+
+ @Test
+ public void test() {
+ createTest()
+ .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
+ .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
+ }
+}
+
+
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 d3fdb7b..bf68f3e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -22,7 +22,7 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.NinePatchDrawable;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.ExactComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
@@ -30,11 +30,13 @@
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.testinfrastructure.CanvasClient;
import android.uirendering.cts.R;
+import org.junit.Test;
+@MediumTest
public class ExactCanvasTests extends ActivityTestBase {
private final BitmapComparer mExactComparer = new ExactComparer();
- @SmallTest
+ @Test
public void testBlueRect() {
final Rect rect = new Rect(10, 10, 80, 80);
createTest()
@@ -50,7 +52,7 @@
.runWithVerifier(new RectVerifier(Color.WHITE, Color.BLUE, rect));
}
- @SmallTest
+ @Test
public void testPoints() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -68,7 +70,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testBlackRectWithStroke() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -86,7 +88,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testBlackLineOnGreenBack() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -102,7 +104,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testDrawRedRectOnBlueBack() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -117,7 +119,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testDrawLine() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -135,7 +137,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testDrawWhiteScreen() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -147,7 +149,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testBasicText() {
final String testString = "THIS IS A TEST";
createTest()
@@ -164,7 +166,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testBasicColorXfermode() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -177,7 +179,7 @@
.runWithComparer(mExactComparer);
}
- @SmallTest
+ @Test
public void testBluePaddedSquare() {
final NinePatchDrawable ninePatchDrawable = (NinePatchDrawable)
getActivity().getResources().getDrawable(R.drawable.blue_padded_square);
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 bac3629..738dcfb 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -22,7 +22,7 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
@@ -30,7 +30,9 @@
import android.uirendering.cts.testinfrastructure.CanvasClient;
import android.uirendering.cts.R;
+import org.junit.Test;
+@MediumTest
public class FontRenderingTests extends ActivityTestBase {
// Thresholds are barely loose enough for differences between sw and hw renderers.
private static final double REGULAR_THRESHOLD = 0.92;
@@ -67,42 +69,42 @@
.runWithVerifier(new GoldenImageVerifier(goldenBitmap, comparer));
}
- @SmallTest
+ @Test
public void testDefaultFont() {
fontTestBody("sans-serif",
Typeface.NORMAL,
R.drawable.hello1);
}
- @SmallTest
+ @Test
public void testBoldFont() {
fontTestBody("sans-serif",
Typeface.BOLD,
R.drawable.bold1);
}
- @SmallTest
+ @Test
public void testItalicFont() {
fontTestBody("sans-serif",
Typeface.ITALIC,
R.drawable.italic1);
}
- @SmallTest
+ @Test
public void testBoldItalicFont() {
fontTestBody("sans-serif",
Typeface.BOLD | Typeface.ITALIC,
R.drawable.bolditalic1);
}
- @SmallTest
+ @Test
public void testMediumFont() {
fontTestBody("sans-serif-medium",
Typeface.NORMAL,
R.drawable.medium1);
}
- @SmallTest
+ @Test
public void testMediumBoldFont() {
// bold attribute on medium base font = black
fontTestBody("sans-serif-medium",
@@ -110,28 +112,28 @@
R.drawable.black1);
}
- @SmallTest
+ @Test
public void testMediumItalicFont() {
fontTestBody("sans-serif-medium",
Typeface.ITALIC,
R.drawable.mediumitalic1);
}
- @SmallTest
+ @Test
public void testMediumBoldItalicFont() {
fontTestBody("sans-serif-medium",
Typeface.BOLD | Typeface.ITALIC,
R.drawable.blackitalic1);
}
- @SmallTest
+ @Test
public void testLightFont() {
fontTestBody("sans-serif-light",
Typeface.NORMAL,
R.drawable.light1);
}
- @SmallTest
+ @Test
public void testLightBoldFont() {
// bold attribute on light base font = medium
fontTestBody("sans-serif-light",
@@ -139,28 +141,28 @@
R.drawable.medium1);
}
- @SmallTest
+ @Test
public void testLightItalicFont() {
fontTestBody("sans-serif-light",
Typeface.ITALIC,
R.drawable.lightitalic1);
}
- @SmallTest
+ @Test
public void testLightBoldItalicFont() {
fontTestBody("sans-serif-light",
Typeface.BOLD | Typeface.ITALIC,
R.drawable.mediumitalic1);
}
- @SmallTest
+ @Test
public void testThinFont() {
fontTestBody("sans-serif-thin",
Typeface.NORMAL,
R.drawable.thin1);
}
- @SmallTest
+ @Test
public void testThinBoldFont() {
// bold attribute on thin base font = normal
fontTestBody("sans-serif-thin",
@@ -168,28 +170,28 @@
R.drawable.hello1);
}
- @SmallTest
+ @Test
public void testThinItalicFont() {
fontTestBody("sans-serif-thin",
Typeface.ITALIC,
R.drawable.thinitalic1);
}
- @SmallTest
+ @Test
public void testThinBoldItalicFont() {
fontTestBody("sans-serif-thin",
Typeface.BOLD | Typeface.ITALIC,
R.drawable.italic1);
}
- @SmallTest
+ @Test
public void testBlackFont() {
fontTestBody("sans-serif-black",
Typeface.NORMAL,
R.drawable.black1);
}
- @SmallTest
+ @Test
public void testBlackBoldFont() {
// bold attribute on black base font = black
fontTestBody("sans-serif-black",
@@ -197,14 +199,14 @@
R.drawable.black1);
}
- @SmallTest
+ @Test
public void testBlackItalicFont() {
fontTestBody("sans-serif-black",
Typeface.ITALIC,
R.drawable.blackitalic1);
}
- @SmallTest
+ @Test
public void testBlackBoldItalicFont() {
fontTestBody("sans-serif-black",
Typeface.BOLD | Typeface.ITALIC,
@@ -213,42 +215,42 @@
/* condensed fonts */
- @SmallTest
+ @Test
public void testCondensedFont() {
fontTestBody("sans-serif-condensed",
Typeface.NORMAL,
R.drawable.condensed1);
}
- @SmallTest
+ @Test
public void testCondensedBoldFont() {
fontTestBody("sans-serif-condensed",
Typeface.BOLD,
R.drawable.condensedbold1);
}
- @SmallTest
+ @Test
public void testCondensedItalicFont() {
fontTestBody("sans-serif-condensed",
Typeface.ITALIC,
R.drawable.condenseditalic1);
}
- @SmallTest
+ @Test
public void testCondensedBoldItalicFont() {
fontTestBody("sans-serif-condensed",
Typeface.BOLD | Typeface.ITALIC,
R.drawable.condensedbolditalic1);
}
- @SmallTest
+ @Test
public void testCondensedLightFont() {
fontTestBody("sans-serif-condensed-light",
Typeface.NORMAL,
R.drawable.condensedlight1);
}
- @SmallTest
+ @Test
public void testCondensedLightItalicFont() {
fontTestBody("sans-serif-condensed-light",
Typeface.ITALIC,
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 37329af..c070b96 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -16,12 +16,12 @@
package android.uirendering.cts.testclasses;
import android.graphics.Point;
+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.test.suitebuilder.annotation.SmallTest;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
@@ -29,10 +29,12 @@
import android.uirendering.cts.testinfrastructure.CanvasClient;
import android.uirendering.cts.testinfrastructure.ViewInitializer;
import android.view.View;
+import org.junit.Test;
+@MediumTest
public class InfrastructureTests extends ActivityTestBase {
- @SmallTest
+ @Test
public void testScreenshot() {
for (int i = 0 ; i < 500 ; i ++) {
takeScreenshot(new Point());
@@ -45,7 +47,7 @@
* by verifying that two paths that should render differently *do* render
* differently.
*/
- @SmallTest
+ @Test
public void testRenderSpecIsolation() {
CanvasClient canvasClient = new CanvasClient() {
@Override
@@ -70,7 +72,7 @@
.runWithComparer(inverseComparer);
}
- @SmallTest
+ @Test
public void testViewInitializer() {
final Rect clipRect = new Rect(0, 0, 50, 50);
ViewInitializer viewInitializer = new ViewInitializer() {
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 a1338bc..30dbb03 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -23,15 +23,20 @@
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.testinfrastructure.ViewInitializer;
import android.view.View;
import android.uirendering.cts.R;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
public class LayerTests extends ActivityTestBase {
- @SmallTest
+ @Test
public void testLayerPaintAlpha() {
// red channel full strength, other channels 75% strength
// (since 25% alpha red subtracts from them)
@@ -53,7 +58,7 @@
.runWithVerifier(new ColorVerifier(expectedColor));
}
- @SmallTest
+ @Test
public void testLayerPaintColorFilter() {
// Red, fully desaturated. Note that it's not 255/3 in each channel.
// See ColorMatrix#setSaturation()
@@ -73,7 +78,7 @@
.runWithVerifier(new ColorVerifier(expectedColor));
}
- @SmallTest
+ @Test
public void testLayerPaintBlend() {
// Red, drawn underneath opaque white, so output should be white.
// TODO: consider doing more interesting blending test here
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
index 30851b6..d69126c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -17,21 +17,23 @@
import android.graphics.Color;
import android.graphics.Rect;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.R;
-import android.test.suitebuilder.annotation.SmallTest;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import org.junit.Test;
+@MediumTest
public class LayoutTests extends ActivityTestBase {
- @SmallTest
+ @Test
public void testSimpleRedLayout() {
createTest().addLayout(R.layout.simple_red_layout, null, false).runWithVerifier(
new ColorVerifier(Color.RED));
}
- @SmallTest
+ @Test
public void testSimpleRectLayout() {
createTest().addLayout(R.layout.simple_rect_layout, null, false).runWithVerifier(
new RectVerifier(Color.WHITE, Color.BLUE, new Rect(5, 5, 85, 85)));
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 8c00ecc..03f5e89 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -23,7 +23,7 @@
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Typeface;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -33,7 +33,11 @@
import android.view.ViewGroup;
import android.webkit.WebView;
import android.uirendering.cts.R;
+import org.junit.Test;
+import static org.junit.Assert.assertNotNull;
+
+@MediumTest
public class PathClippingTests extends ActivityTestBase {
// draw circle with hole in it, with stroked circle
static final CanvasClient sTorusDrawCanvasClient = new CanvasClient() {
@@ -75,7 +79,7 @@
}
};
- @SmallTest
+ @Test
public void testCircleWithCircle() {
createTest()
.addCanvasClient(sTorusDrawCanvasClient, false)
@@ -83,7 +87,7 @@
.runWithComparer(new MSSIMComparer(0.90));
}
- @SmallTest
+ @Test
public void testCircleWithPoints() {
createTest()
.addCanvasClient(sTorusClipCanvasClient)
@@ -105,7 +109,7 @@
}));
}
- @SmallTest
+ @Test
public void testViewRotate() {
createTest()
.addLayout(R.layout.blue_padded_layout, new ViewInitializer() {
@@ -137,7 +141,7 @@
}));
}
- @SmallTest
+ @Test
public void testTextClip() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -162,7 +166,7 @@
.runWithComparer(new MSSIMComparer(0.90));
}
- @SmallTest
+ @Test
public void testWebViewClipWithCircle() {
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
return; // no WebView to run test on
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 6619b11..9c8f9ba 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
@@ -21,18 +21,20 @@
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Rect;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
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
public class PictureTest extends ActivityTestBase {
private static final Rect sRect = new Rect(0, 0, 40, 40);
private static final Rect sOffsetRect = new Rect(40, 0, 80, 40);
- private static final Picture greenSquare() {
+ private static Picture greenSquare() {
Paint pt = new Paint();
pt.setColor(Color.GREEN);
Picture pic = new Picture();
@@ -44,6 +46,7 @@
return pic;
}
+ @Test
public void testPictureRespectsClip() throws Exception {
createTest()
.addCanvasClient(
@@ -58,6 +61,7 @@
).runWithVerifier(new ColorVerifier(Color.WHITE));
}
+ @Test
public void testPictureRespectsTranslate() throws Exception {
createTest()
.addCanvasClient(
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
index 6500681..16a38e8 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
@@ -25,15 +25,17 @@
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.Shader;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.testinfrastructure.CanvasClient;
import android.uirendering.cts.R;
+import org.junit.Test;
+@MediumTest
public class ShaderTests extends ActivityTestBase {
- @SmallTest
+ @Test
public void testSinglePixelBitmapShader() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -52,7 +54,7 @@
.runWithVerifier(new ColorVerifier(Color.BLUE));
}
- @SmallTest
+ @Test
public void testSinglePixelComposeShader() {
createTest()
.addCanvasClient(new CanvasClient() {
@@ -83,7 +85,7 @@
.runWithVerifier(new ColorVerifier(Color.BLUE));
}
- @SmallTest
+ @Test
public void testComplexShaderUsage() {
/*
* This test not only builds a very complex drawing operation, but also tests an
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
index 26c2402..6b9fb79 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -17,23 +17,40 @@
import android.graphics.Color;
import android.graphics.Point;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.R;
-import android.test.suitebuilder.annotation.SmallTest;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.util.CompareUtils;
+import org.junit.Test;
+@MediumTest
public class ShadowTests extends ActivityTestBase {
- @SmallTest
+
+ private class GrayScaleVerifier extends SamplePointVerifier {
+ public GrayScaleVerifier(Point[] testPoints, int[] expectedColors, int tolerance) {
+ super(testPoints, expectedColors, tolerance) ;
+ }
+
+ @Override
+ protected boolean verifyPixel(int color, int expectedColor) {
+ return super.verifyPixel(color, expectedColor)
+ && CompareUtils.verifyPixelGrayScale(color, 1);
+ }
+ }
+
+ @Test
public void testShadowLayout() {
int shadowColorValue = 0xDB;
// Android TV theme overrides shadow opacity to be darker.
if (getActivity().getOnTv()) {
shadowColorValue = 0xBB;
}
- // Use a higher threshold (36) than default value (20);
- SamplePointVerifier verifier = new SamplePointVerifier(
+
+ // Use a higher threshold than default value (20), since we also double check gray scale;
+ GrayScaleVerifier verifier = new GrayScaleVerifier(
new Point[] {
// view area
new Point(25, 64),
@@ -48,7 +65,8 @@
Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
},
- 36);
+ 48);
+
createTest()
.addLayout(R.layout.simple_shadow_layout, null, true/* HW only */)
.runWithVerifier(verifier);
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 71b4f3f..f5f59b3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -20,21 +20,16 @@
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.graphics.Shader;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
-import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
-import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.testinfrastructure.CanvasClient;
import android.uirendering.cts.testinfrastructure.DisplayModifier;
import android.uirendering.cts.testinfrastructure.ResourceModifier;
+import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -42,222 +37,8 @@
/**
* Test cases of all combination of resource modifications.
*/
+@MediumTest
public class SweepTests extends ActivityTestBase {
- private static final String TAG = "SweepTests";
-
- public static final int BG_COLOR = 0xFFFFFFFF;
- public static final int DST_COLOR = 0xFFFFCC44;
- public static final int SRC_COLOR = 0xFF66AAFF;
- public static final int MULTIPLY_COLOR = 0xFF668844;
- public static final int SCREEN_COLOR = 0xFFFFEEFF;
-
- // These points are in pairs, the first being the lower left corner, the second is only in the
- // Destination bitmap, the third is the intersection of the two bitmaps, and the fourth is in
- // the Source bitmap.
- private final static Point[] XFERMODE_TEST_POINTS = new Point[] {
- new Point(1, 80), new Point(25, 25), new Point(35, 35), new Point(70, 70)
- };
-
- /**
- * There are 4 locations we care about in any filter testing.
- *
- * 1) Both empty
- * 2) Only src, dst empty
- * 3) Both src + dst
- * 4) Only dst, src empty
- */
- private final Map<PorterDuff.Mode, int[]> XFERMODE_COLOR_MAP = new LinkedHashMap<PorterDuff.Mode, int[]>() {
- {
- put(PorterDuff.Mode.SRC, new int[] {
- BG_COLOR, BG_COLOR, SRC_COLOR, SRC_COLOR
- });
-
- put(PorterDuff.Mode.DST, new int[] {
- BG_COLOR, DST_COLOR, DST_COLOR, BG_COLOR
- });
-
- put(PorterDuff.Mode.SRC_OVER, new int[] {
- BG_COLOR, DST_COLOR, SRC_COLOR, SRC_COLOR
- });
-
- put(PorterDuff.Mode.DST_OVER, new int[] {
- BG_COLOR, DST_COLOR, DST_COLOR, SRC_COLOR
- });
-
- put(PorterDuff.Mode.SRC_IN, new int[] {
- BG_COLOR, BG_COLOR, SRC_COLOR, BG_COLOR
- });
-
- put(PorterDuff.Mode.DST_IN, new int[] {
- BG_COLOR, BG_COLOR, DST_COLOR, BG_COLOR
- });
-
- put(PorterDuff.Mode.SRC_OUT, new int[] {
- BG_COLOR, BG_COLOR, BG_COLOR, SRC_COLOR
- });
-
- put(PorterDuff.Mode.DST_OUT, new int[] {
- BG_COLOR, DST_COLOR, BG_COLOR, BG_COLOR
- });
-
- put(PorterDuff.Mode.SRC_ATOP, new int[] {
- BG_COLOR, DST_COLOR, SRC_COLOR, BG_COLOR
- });
-
- put(PorterDuff.Mode.DST_ATOP, new int[] {
- BG_COLOR, BG_COLOR, DST_COLOR, SRC_COLOR
- });
-
- put(PorterDuff.Mode.XOR, new int[] {
- BG_COLOR, DST_COLOR, BG_COLOR, SRC_COLOR
- });
-
- put(PorterDuff.Mode.MULTIPLY, new int[] {
- BG_COLOR, BG_COLOR, MULTIPLY_COLOR, BG_COLOR
- });
-
- put(PorterDuff.Mode.SCREEN, new int[] {
- BG_COLOR, DST_COLOR, SCREEN_COLOR, SRC_COLOR
- });
- }
- };
-
- private final static DisplayModifier XFERMODE_MODIFIER = new DisplayModifier() {
- private final RectF mSrcRect = new RectF(30, 30, 80, 80);
- private final RectF mDstRect = new RectF(10, 10, 60, 60);
- private final Bitmap mSrcBitmap = createSrc();
- private final Bitmap mDstBitmap = createDst();
-
- @Override
- public void modifyDrawing(Paint paint, Canvas canvas) {
- int sc = canvas.saveLayer(0, 0, TEST_WIDTH, TEST_HEIGHT, null);
-
- canvas.drawBitmap(mDstBitmap, 0, 0, null);
- canvas.drawBitmap(mSrcBitmap, 0, 0, paint);
-
- canvas.restoreToCount(sc);
- }
-
- private Bitmap createSrc() {
- Bitmap srcB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
- Canvas srcCanvas = new Canvas(srcB);
- Paint srcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- srcPaint.setColor(SRC_COLOR);
- srcCanvas.drawRect(mSrcRect, srcPaint);
- return srcB;
- }
-
- private Bitmap createDst() {
- Bitmap dstB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
- Canvas dstCanvas = new Canvas(dstB);
- Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- dstPaint.setColor(DST_COLOR);
- dstCanvas.drawOval(mDstRect, dstPaint);
- return dstB;
- }
- };
-
- // We care about one point in each of the four rectangles of different alpha values, as well as
- // the area outside the rectangles
- private final static Point[] COLOR_FILTER_ALPHA_POINTS = new Point[] {
- new Point(9, 45),
- new Point(27, 45),
- new Point(45, 45),
- new Point(63, 45),
- new Point(81, 45)
- };
-
- public static final int FILTER_COLOR = 0xFFBB0000;
- private final Map<PorterDuff.Mode, int[]> COLOR_FILTER_ALPHA_MAP
- = new LinkedHashMap<PorterDuff.Mode, int[]>() {
- {
- put(PorterDuff.Mode.SRC, new int[] {
- FILTER_COLOR, FILTER_COLOR, FILTER_COLOR, FILTER_COLOR, FILTER_COLOR
- });
-
- put(PorterDuff.Mode.DST, new int[] {
- 0xFFE6E6E6, 0xFFCCCCCC, 0xFFB3B3B3, 0xFF999999, 0xFFFFFFFF
- });
-
- put(PorterDuff.Mode.SRC_OVER, new int[] {
- 0xFFBB0000, 0xFFBB0000, 0xFFBB0000, 0xFFBB0000, 0xFFBB0000
- });
-
- put(PorterDuff.Mode.DST_OVER, new int[] {
- 0xFFAF1A1A, 0xFFA33333, 0xFF984D4D, 0xFF8B6666, 0xFFBB0000
- });
-
- put(PorterDuff.Mode.SRC_IN, new int[] {
- 0xFFF1CCCC, 0xFFE49999, 0xFFD66666, 0xFFC83333, 0xFFFFFFFF
- });
-
- put(PorterDuff.Mode.DST_IN, new int[] {
- 0xFFE6E6E6, 0xFFCCCCCC, 0xFFB3B3B3, 0xFF999999, 0xFFFFFFFF
- });
-
- put(PorterDuff.Mode.SRC_OUT, new int[] {
- 0xFFC83333, 0xFFD66666, 0xFFE49999, 0xFFF1CCCC, 0xFFBB0000
- });
-
- put(PorterDuff.Mode.DST_OUT, new int[] {
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
- });
-
- put(PorterDuff.Mode.SRC_ATOP, new int[] {
- 0xFFF1CCCC, 0xFFE49999, 0xFFD66666, 0xFFC93333, 0xFFFFFFFF
- });
-
- put(PorterDuff.Mode.DST_ATOP, new int[] {
- 0xFFB01A1A, 0xFFA33333, 0xFF984D4D, 0xFF8B6666, 0xFFBB0000
- });
-
- put(PorterDuff.Mode.XOR, new int[] {
- 0xFFC93333, 0xFFD66666, 0xFFE49999, 0xFFF1CCCC, 0xFFBB0000
- });
-
- put(PorterDuff.Mode.MULTIPLY, new int[] {
- 0xFFDFCCCC, 0xFFBE9999, 0xFF9E6666, 0xFF7E3333, 0xFFFFFFFF
- });
-
- put(PorterDuff.Mode.SCREEN, new int[] {
- 0xFFC21A1A, 0xFFC93333, 0xFFD04D4D, 0xFFD66666, 0xFFBB0000
- });
- }
- };
-
- /**
- * Draws 5 blocks of different color/opacity to be blended against
- */
- private final static DisplayModifier COLOR_FILTER_ALPHA_MODIFIER = new DisplayModifier() {
- private final int[] BLOCK_COLORS = new int[] {
- 0x33808080,
- 0x66808080,
- 0x99808080,
- 0xCC808080,
- 0x00000000
- };
-
- private final Bitmap mBitmap = createQuadRectBitmap();
-
- public void modifyDrawing(Paint paint, Canvas canvas) {
- canvas.drawBitmap(mBitmap, 0, 0, paint);
- }
-
- private Bitmap createQuadRectBitmap() {
- Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- final int blockCount = BLOCK_COLORS.length;
- final int blockWidth = TEST_WIDTH / blockCount;
- for (int i = 0 ; i < blockCount; i++) {
- paint.setColor(BLOCK_COLORS[i]);
- canvas.drawRect(i * blockWidth, 0, (i + 1) * blockWidth, TEST_HEIGHT, paint);
- }
- return bitmap;
- }
- };
-
private final static DisplayModifier COLOR_FILTER_GRADIENT_MODIFIER = new DisplayModifier() {
private final Rect mBounds = new Rect(30, 30, 150, 150);
private final int[] mColors = new int[] {
@@ -299,54 +80,25 @@
new MSSIMComparer(HIGH_THRESHOLD)
};
- @SmallTest
+ @Test
public void testBasicDraws() {
- sweepModifiersForMask(DisplayModifier.Accessor.SHAPES_MASK, null, DEFAULT_MSSIM_COMPARER,
- null);
+ sweepModifiersForMask(DisplayModifier.Accessor.SHAPES_MASK, null, DEFAULT_MSSIM_COMPARER);
}
- @SmallTest
+ @Test
public void testBasicShaders() {
sweepModifiersForMask(DisplayModifier.Accessor.SHADER_MASK, mCircleDrawModifier,
- DEFAULT_MSSIM_COMPARER, null);
+ DEFAULT_MSSIM_COMPARER);
}
- @SmallTest
+ @Test
public void testColorFilterUsingGradient() {
sweepModifiersForMask(DisplayModifier.Accessor.COLOR_FILTER_MASK,
- COLOR_FILTER_GRADIENT_MODIFIER, DEFAULT_MSSIM_COMPARER, null);
- }
-
- @SmallTest
- public void testColorFiltersAlphas() {
- BitmapVerifier[] bitmapVerifiers =
- new BitmapVerifier[DisplayModifier.PORTERDUFF_MODES.length];
- int index = 0;
- for (PorterDuff.Mode mode : DisplayModifier.PORTERDUFF_MODES) {
- bitmapVerifiers[index] = new SamplePointVerifier(COLOR_FILTER_ALPHA_POINTS,
- COLOR_FILTER_ALPHA_MAP.get(mode));
- index++;
- }
- sweepModifiersForMask(DisplayModifier.Accessor.COLOR_FILTER_MASK,
- COLOR_FILTER_ALPHA_MODIFIER, null, bitmapVerifiers);
- }
-
- @SmallTest
- public void testXfermodes() {
- BitmapVerifier[] bitmapVerifiers =
- new BitmapVerifier[DisplayModifier.PORTERDUFF_MODES.length];
- int index = 0;
- for (PorterDuff.Mode mode : DisplayModifier.PORTERDUFF_MODES) {
- bitmapVerifiers[index] = new SamplePointVerifier(XFERMODE_TEST_POINTS,
- XFERMODE_COLOR_MAP.get(mode));
- index++;
- }
- sweepModifiersForMask(DisplayModifier.Accessor.XFERMODE_MASK, XFERMODE_MODIFIER,
- null, bitmapVerifiers);
+ COLOR_FILTER_GRADIENT_MODIFIER, DEFAULT_MSSIM_COMPARER);
}
protected void sweepModifiersForMask(int mask, final DisplayModifier drawOp,
- BitmapComparer[] bitmapComparers, BitmapVerifier[] bitmapVerifiers) {
+ BitmapComparer[] bitmapComparers) {
if ((mask & DisplayModifier.Accessor.ALL_OPTIONS_MASK) == 0) {
throw new IllegalArgumentException("Attempt to test with a mask that is invalid");
}
@@ -371,13 +123,8 @@
// Create the test cases with each combination
do {
canvasClient.setDebugString(modifierAccessor.getDebugString());
- if (bitmapComparers != null) {
- int arrIndex = Math.min(index, bitmapComparers.length - 1);
- createTest().addCanvasClient(canvasClient).runWithComparer(bitmapComparers[arrIndex]);
- } else {
- int arrIndex = Math.min(index, bitmapVerifiers.length - 1);
- createTest().addCanvasClient(canvasClient).runWithVerifier(bitmapVerifiers[arrIndex]);
- }
+ int arrIndex = Math.min(index, bitmapComparers.length - 1);
+ createTest().addCanvasClient(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 2db635f0..3b1df30 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -3,6 +3,7 @@
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Rect;
+import android.test.suitebuilder.annotation.MediumTest;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.testclasses.view.UnclippedBlueView;
@@ -12,6 +13,7 @@
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.uirendering.cts.R;
+import org.junit.Test;
/**
* This tests view clipping by modifying properties of blue_padded_layout, and validating
@@ -19,6 +21,7 @@
*
* Since the layout is blue on a white background, this is always done with a RectVerifier.
*/
+@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);
@@ -66,30 +69,35 @@
return new RectVerifier(Color.WHITE, Color.BLUE, blueBoundsRect, 75);
}
+ @Test
public void testSimpleUnclipped() {
createTest()
.addLayout(R.layout.blue_padded_layout, null)
.runWithVerifier(makeClipVerifier(FULL_RECT));
}
+ @Test
public void testSimpleBoundsClip() {
createTest()
.addLayout(R.layout.blue_padded_layout, BOUNDS_CLIP_INIT)
.runWithVerifier(makeClipVerifier(BOUNDS_RECT));
}
+ @Test
public void testSimpleClipBoundsClip() {
createTest()
.addLayout(R.layout.blue_padded_layout, CLIP_BOUNDS_CLIP_INIT)
.runWithVerifier(makeClipVerifier(CLIP_BOUNDS_RECT));
}
+ @Test
public void testSimplePaddingClip() {
createTest()
.addLayout(R.layout.blue_padded_layout, PADDING_CLIP_INIT)
.runWithVerifier(makeClipVerifier(PADDED_RECT));
}
+ @Test
public void testSimpleOutlineClip() {
// NOTE: Only HW is supported
createTest()
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
new file mode 100644
index 0000000..c6e9881
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.uirendering.cts.testclasses;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class XfermodeTest extends ActivityTestBase {
+ /**
+ * There are 4 locations we care about in testing each filter:
+ *
+ * 1) Both empty
+ * 2) Only src, dst empty
+ * 3) Both src + dst
+ * 4) Only dst, src empty
+ */
+ private final static Point[] TEST_POINTS = new Point[] {
+ new Point(1, 80),
+ new Point(25, 25),
+ new Point(35, 35),
+ new Point(70, 70)
+ };
+
+ public static class Config {
+ final boolean hardwareAccelerated;
+ final PorterDuff.Mode mode;
+ final int[] expectedColors;
+
+ Config(boolean hardwareAccelerated, Object[] modeAndExpectedColors) {
+ this.hardwareAccelerated = hardwareAccelerated;
+ mode = (PorterDuff.Mode) modeAndExpectedColors[0];
+ expectedColors = (int[]) modeAndExpectedColors[1];
+ }
+
+ @Override
+ public String toString() {
+ return mode.name() + ", hardwareAccelerated=" + hardwareAccelerated;
+ }
+ };
+
+ public static List<XfermodeTest.Config> configs(Object[][] modesAndExpectedColors) {
+ List<XfermodeTest.Config> configs = new ArrayList<>();
+ for (boolean hardwareAccelerated : new boolean[] {false, true}) {
+ for (Object[] modeAndExpectedColors : modesAndExpectedColors) {
+ configs.add(new XfermodeTest.Config(hardwareAccelerated, modeAndExpectedColors));
+ }
+ }
+ return configs;
+ }
+
+ private static final int BG_COLOR = 0xFFFFFFFF;
+ private static final int DST_COLOR = 0xFFFFCC44;
+ private static final int SRC_COLOR = 0xFF66AAFF;
+ private static final int MULTIPLY_COLOR = 0xFF668844;
+ private static final int SCREEN_COLOR = 0xFFFFEEFF;
+
+ private static Object[][] MODES_AND_EXPECTED_COLORS = new Object[][] {
+ { PorterDuff.Mode.SRC, new int[] {
+ BG_COLOR, BG_COLOR, SRC_COLOR, SRC_COLOR } },
+
+ { PorterDuff.Mode.DST, new int[] {
+ BG_COLOR, DST_COLOR, DST_COLOR, BG_COLOR } },
+
+ { PorterDuff.Mode.SRC_OVER, new int[] {
+ BG_COLOR, DST_COLOR, SRC_COLOR, SRC_COLOR } },
+
+ { PorterDuff.Mode.DST_OVER, new int[] {
+ BG_COLOR, DST_COLOR, DST_COLOR, SRC_COLOR } },
+
+ { PorterDuff.Mode.SRC_IN, new int[] {
+ BG_COLOR, BG_COLOR, SRC_COLOR, BG_COLOR } },
+
+ { PorterDuff.Mode.DST_IN, new int[] {
+ BG_COLOR, BG_COLOR, DST_COLOR, BG_COLOR } },
+
+ { PorterDuff.Mode.SRC_OUT, new int[] {
+ BG_COLOR, BG_COLOR, BG_COLOR, SRC_COLOR } },
+
+ { PorterDuff.Mode.DST_OUT, new int[] {
+ BG_COLOR, DST_COLOR, BG_COLOR, BG_COLOR } },
+
+ { PorterDuff.Mode.SRC_ATOP, new int[] {
+ BG_COLOR, DST_COLOR, SRC_COLOR, BG_COLOR } },
+
+ { PorterDuff.Mode.DST_ATOP, new int[] {
+ BG_COLOR, BG_COLOR, DST_COLOR, SRC_COLOR } },
+
+ { PorterDuff.Mode.XOR, new int[] {
+ BG_COLOR, DST_COLOR, BG_COLOR, SRC_COLOR } },
+
+ { PorterDuff.Mode.MULTIPLY, new int[] {
+ BG_COLOR, BG_COLOR, MULTIPLY_COLOR, BG_COLOR } },
+
+ { PorterDuff.Mode.SCREEN, new int[] {
+ BG_COLOR, DST_COLOR, SCREEN_COLOR, SRC_COLOR } },
+ };
+
+ @Parameterized.Parameters(name = "{0}")
+ public static List<Config> configs() {
+ return configs(MODES_AND_EXPECTED_COLORS);
+ }
+
+ private final Config mConfig;
+
+ public XfermodeTest(Config config) {
+ mConfig = config;
+ }
+
+ private CanvasClient mCanvasClient = new CanvasClient() {
+ final Paint mPaint = new Paint();
+ private final RectF mSrcRect = new RectF(30, 30, 80, 80);
+ private final RectF mDstRect = new RectF(10, 10, 60, 60);
+ private final Bitmap mSrcBitmap = createSrc();
+ private final Bitmap mDstBitmap = createDst();
+
+ @Override
+ public void draw(Canvas canvas, int width, int height) {
+ int sc = canvas.saveLayer(0, 0, TEST_WIDTH, TEST_HEIGHT, null);
+
+ canvas.drawBitmap(mDstBitmap, 0, 0, null);
+ mPaint.setXfermode(new PorterDuffXfermode(mConfig.mode));
+ canvas.drawBitmap(mSrcBitmap, 0, 0, mPaint);
+
+ canvas.restoreToCount(sc);
+ }
+
+ private Bitmap createSrc() {
+ Bitmap srcB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
+ Canvas srcCanvas = new Canvas(srcB);
+ Paint srcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ srcPaint.setColor(SRC_COLOR);
+ srcCanvas.drawRect(mSrcRect, srcPaint);
+ return srcB;
+ }
+
+ private Bitmap createDst() {
+ Bitmap dstB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
+ Canvas dstCanvas = new Canvas(dstB);
+ Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ dstPaint.setColor(DST_COLOR);
+ dstCanvas.drawOval(mDstRect, dstPaint);
+ return dstB;
+ }
+ };
+
+ @Test
+ public void test() {
+ createTest()
+ .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
+ .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
+ }
+}
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 69cb688..f82bb40 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -16,11 +16,13 @@
package android.uirendering.cts.testinfrastructure;
import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.Instrumentation;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.renderscript.Allocation;
import android.renderscript.RenderScript;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.rule.ActivityTestRule;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
@@ -29,18 +31,23 @@
import android.util.Log;
import android.support.test.InstrumentationRegistry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import static org.junit.Assert.assertTrue;
+
/**
* This class contains the basis for the graphics hardware test classes. Contained within this class
* are several methods that help with the execution of tests, and should be extended to gain the
* functionality built in.
*/
-public abstract class ActivityTestBase extends
- ActivityInstrumentationTestCase2<DrawActivity> {
+public abstract class ActivityTestBase {
public static final String TAG = "ActivityTestBase";
public static final boolean DEBUG = false;
public static final boolean USE_RS = false;
@@ -57,12 +64,18 @@
private RenderScript mRenderScript;
private TestCaseBuilder mTestCaseBuilder;
+ @Rule
+ public ActivityTestRule<DrawActivity> mActivityRule = new ActivityTestRule<>(
+ DrawActivity.class);
+
+ @Rule
+ public TestName name = new TestName();
+
/**
* The default constructor creates the package name and sets the DrawActivity as the class that
* we would use.
*/
public ActivityTestBase() {
- super(DrawActivity.class);
mDifferenceVisualizer = new PassFailVisualizer();
// Create a location for the files to be held, if it doesn't exist already
@@ -74,26 +87,27 @@
}
}
- /**
- * This method is called before each test case and should be called from the test class that
- * extends this class.
- */
- @Override
+ protected DrawActivity getActivity() {
+ return mActivityRule.getActivity();
+ }
+
+ protected String getName() {
+ return name.getMethodName();
+ }
+
+ protected Instrumentation getInstrumentation() {
+ return InstrumentationRegistry.getInstrumentation();
+ }
+
+ @Before
public void setUp() {
- // As the way to access Instrumentation is changed in the new runner, we need to inject it
- // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
- // be marked as deprecated and replaced with ActivityTestRule.
- injectInstrumentation(InstrumentationRegistry.getInstrumentation());
mDifferenceVisualizer = new PassFailVisualizer();
if (USE_RS) {
mRenderScript = RenderScript.create(getActivity().getApplicationContext());
}
}
- /**
- * This method will kill the activity so that it can be reset depending on the test.
- */
- @Override
+ @After
public void tearDown() {
if (mTestCaseBuilder != null) {
List<TestCase> testCases = mTestCaseBuilder.getTestCases();
@@ -102,7 +116,6 @@
throw new IllegalStateException("Must have at least one test case");
}
-
for (TestCase testCase : testCases) {
if (!testCase.wasTestRan) {
Log.w(TAG, getName() + " not all of the tests ran");
@@ -111,16 +124,6 @@
}
mTestCaseBuilder = null;
}
-
- Runnable finishRunnable = new Runnable() {
-
- @Override
- public void run() {
- getActivity().finish();
- }
- };
-
- getActivity().runOnUiThread(finishRunnable);
}
public Bitmap takeScreenshot(Point testOffset) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/CompareUtils.java b/tests/tests/uirendering/src/android/uirendering/cts/util/CompareUtils.java
index 4f246a4..c80a778 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/CompareUtils.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/CompareUtils.java
@@ -12,4 +12,17 @@
+ Math.abs(Color.blue(color) - Color.blue(expectedColor));
return diff <= threshold;
}
+
+ /**
+ * @param threshold Per channel differences for R / G / B channel against the average of these 3
+ * channels. Should be less than 2 normally.
+ * @return True if the color is close enough to be a gray scale color.
+ */
+ public static boolean verifyPixelGrayScale(int color, int threshold) {
+ int average = Color.red(color) + Color.green(color) + Color.blue(color);
+ average /= 3;
+ return Math.abs(Color.red(color) - average) <= threshold
+ && Math.abs(Color.green(color) - average) <= threshold
+ && Math.abs(Color.blue(color) - average) <= threshold;
+ }
}
diff --git a/tests/tests/util/src/android/util/cts/EventLogTest.java b/tests/tests/util/src/android/util/cts/EventLogTest.java
index 2d856c4..2065e32 100644
--- a/tests/tests/util/src/android/util/cts/EventLogTest.java
+++ b/tests/tests/util/src/android/util/cts/EventLogTest.java
@@ -77,7 +77,7 @@
assertEquals(7, events.size());
// subtract: log header, type byte, final newline
- final int max = 4096 - 20 - 4 - 1;
+ final int max = 4096 - 20 - 4 - 1 - 8;
// subtract: string header (type + length)
String val0 = (String) events.get(0).getData();
diff --git a/tests/tests/util/src/android/util/cts/LocaleListTest.java b/tests/tests/util/src/android/util/cts/LocaleListTest.java
index 456b26e..e64d955 100644
--- a/tests/tests/util/src/android/util/cts/LocaleListTest.java
+++ b/tests/tests/util/src/android/util/cts/LocaleListTest.java
@@ -312,6 +312,14 @@
assertEquals(original, cloneViaParcel(original));
}
+ public void testDescribeContents_doesNotThrowException() {
+ // Just check calling describeContents() should not cause any exceptions.
+ LocaleList.forLanguageTags("en").describeContents();
+ LocaleList.forLanguageTags("").describeContents();
+ LocaleList.forLanguageTags(null).describeContents();
+ LocaleList.getEmptyLocaleList().describeContents();
+ }
+
private static LocaleList cloneViaParcel(final LocaleList original) {
Parcel parcel = null;
try {
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index eb6cee7..57dc0ce 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -28,7 +28,8 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil ctstestrunner mockito-target platform-test-annotations
LOCAL_JNI_SHARED_LIBRARIES := libctsview_jni libnativehelper_compat_libc++
diff --git a/tests/tests/view/AndroidTest.xml b/tests/tests/view/AndroidTest.xml
index def111d..c818923 100644
--- a/tests/tests/view/AndroidTest.xml
+++ b/tests/tests/view/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.view.cts" />
+ <option name="runtime-hint" value="6m47s" />
</test>
</configuration>
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index 9769aa4..c576350 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -123,4 +123,14 @@
</LinearLayout>
</LinearLayout>
+ <FrameLayout
+ android:id="@+id/aggregate_visibility_parent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <android.view.cts.MockView
+ android:id="@+id/mock_view_aggregate_visibility"
+ android:layout_width="10px"
+ android:layout_height="10px" />
+ </FrameLayout>
+
</LinearLayout>
diff --git a/tests/tests/view/src/android/view/cts/ContentPaneCtsActivity.java b/tests/tests/view/src/android/view/cts/ContentPaneCtsActivity.java
index 5d7b354..f6315c8 100644
--- a/tests/tests/view/src/android/view/cts/ContentPaneCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ContentPaneCtsActivity.java
@@ -19,8 +19,7 @@
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
-import android.view.MenuItem;
-import android.view.cts.R;
+import android.view.Window;
/**
* A simple activity to test "Focus Handling"
@@ -30,6 +29,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(android.R.style.Theme_Material_Light);
+ getWindow().requestFeature(Window.FEATURE_OPTIONS_PANEL);
setContentView(R.layout.viewtreeobserver_layout);
}
diff --git a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
index c99679b..eaaea74 100644
--- a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
+++ b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
@@ -16,13 +16,16 @@
package android.view.cts;
+import android.app.ActionBar;
import android.app.Activity;
+import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.cts.R;
+import android.view.ViewGroup;
+import android.view.ViewParent;
public class ContentPaneFocusTest
extends ActivityInstrumentationTestCase2<ContentPaneCtsActivity> {
@@ -45,12 +48,34 @@
sendControlChar('<');
getInstrumentation().waitForIdleSync();
+ ActionBar action = activity.getActionBar();
+ if (action == null || !action.isShowing()) {
+ // No action bar, so we only needed to make sure that the shortcut didn't cause
+ // the framework to crash.
+ return;
+ }
+
+ final View content = activity.findViewById(android.R.id.content);
+ assertNotNull(content);
+ final ViewParent viewParent = content.getParent();
+ assertNotNull(viewParent);
+ assertTrue(viewParent instanceof ViewGroup);
+ ViewGroup parent = (ViewGroup) viewParent;
+ View actionBarView = null;
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ View child = parent.getChildAt(i);
+ if ("android:action_bar".equals(child.getTransitionName())) {
+ actionBarView = child;
+ break;
+ }
+ }
+ assertNotNull(actionBarView);
+ final View actionBar = actionBarView;
// Should jump to the action bar after control-<
runTestOnUiThread(new Runnable() {
@Override
public void run() {
assertFalse(v1.hasFocus());
- View actionBar = activity.findViewById(com.android.internal.R.id.action_bar);
assertTrue(actionBar.hasFocus());
}
});
@@ -67,25 +92,42 @@
getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
getInstrumentation().waitForIdleSync();
- // Now it shouldn't go up to action bar -- it doesn't allow taking focus once left
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- assertTrue(v1.hasFocus());
- }
- });
+ boolean isTouchScreen = activity.getPackageManager().
+ hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+ if (isTouchScreen) {
+ // Now it shouldn't go up to action bar -- it doesn't allow taking focus once left
+ // but only for touch screens.
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(v1.hasFocus());
+ }
+ });
+ }
}
private void sendControlChar(char key) throws Throwable {
KeyEvent tempEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
KeyCharacterMap map = tempEvent.getKeyCharacterMap();
+ sendControlKey(KeyEvent.ACTION_DOWN);
KeyEvent[] events = map.getEvents(new char[] {key});
+ final int controlOn = KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON;
for (int i = 0; i < events.length; i++) {
long time = SystemClock.uptimeMillis();
KeyEvent event = events[i];
KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
- event.getRepeatCount(), event.getMetaState() | KeyEvent.META_CTRL_ON);
+ event.getRepeatCount(), event.getMetaState() | controlOn);
getInstrumentation().sendKeySync(controlKey);
+ Thread.sleep(2);
}
+ sendControlKey(KeyEvent.ACTION_UP);
+ }
+
+ private void sendControlKey(int action) throws Throwable {
+ long time = SystemClock.uptimeMillis();
+ KeyEvent keyEvent = new KeyEvent(time, time, action, KeyEvent.KEYCODE_CTRL_LEFT, 0,
+ KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON);
+ getInstrumentation().sendKeySync(keyEvent);
+ Thread.sleep(2);
}
}
diff --git a/tests/tests/view/src/android/view/cts/MockView.java b/tests/tests/view/src/android/view/cts/MockView.java
index 0a56369..3e140c2 100644
--- a/tests/tests/view/src/android/view/cts/MockView.java
+++ b/tests/tests/view/src/android/view/cts/MockView.java
@@ -70,10 +70,13 @@
private boolean mCalledDispatchKeyEventPreIme = false;
private boolean mCalledOnKeyPreIme = false;
private boolean mCalledGetPointerIcon = false;
+ private boolean mCalledOnVisibilityAggregated = false;
private int mOldWidth = -1;
private int mOldHeight = -1;
+ private boolean mLastAggregatedVisibility;
+
public MockView(Context context) {
super(context);
}
@@ -616,6 +619,21 @@
return mCalledGetPointerIcon;
}
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
+ mCalledOnVisibilityAggregated = true;
+ mLastAggregatedVisibility = isVisible;
+ }
+
+ public boolean hasCalledOnVisibilityAggregated() {
+ return mCalledOnVisibilityAggregated;
+ }
+
+ public boolean getLastAggregatedVisibility() {
+ return mLastAggregatedVisibility;
+ }
+
public void reset() {
mCalledOnCreateContextMenu = false;
@@ -655,8 +673,10 @@
mCalledDispatchKeyEventPreIme = false;
mCalledOnKeyPreIme = false;
mCalledGetPointerIcon = false;
+ mCalledOnVisibilityAggregated = false;
mOldWidth = -1;
mOldHeight = -1;
+ mLastAggregatedVisibility = false;
}
}
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java b/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java
index c4cebb9..46f66ce 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java
@@ -23,6 +23,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
@@ -57,6 +58,7 @@
mContext = getInstrumentation().getTargetContext();
}
+ @Presubmit
public void testBasics() {
DrawingUtils.assertAllPixelsOfColor("Default fill", mViewGroupWithOverlay,
Color.WHITE, null);
@@ -396,4 +398,4 @@
mViewGroupWithOverlay, Color.WHITE, colorRectangles);
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 10e743a..49979ca 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -27,7 +27,6 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.BitmapDrawable;
-import android.os.Build;
import android.os.Parcelable;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
@@ -1011,18 +1010,6 @@
assertEquals(2, rect.top);
assertEquals(1, rect.left);
assertEquals(1, rect.right);
-
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || Build.VERSION.CODENAME.equals("N")) {
- textView.setTranslationX(2);
- textView.setTranslationY(1);
-
- rect.setEmpty();
- vg.offsetDescendantRectToMyCoords(textView, rect);
- assertEquals(3, rect.bottom);
- assertEquals(3, rect.top);
- assertEquals(3, rect.left);
- assertEquals(3, rect.right);
- }
}
public void testOffsetRectIntoDescendantCoords() {
@@ -1046,18 +1033,6 @@
assertEquals(4, rect.top);
assertEquals(4, rect.left);
assertEquals(6, rect.right);
-
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || Build.VERSION.CODENAME.equals("N")) {
- textView.setTranslationX(2);
- textView.setTranslationY(1);
-
- rect.set(5, 6, 7, 8);
- vg.offsetRectIntoDescendantCoords(textView, rect);
- assertEquals(5, rect.bottom);
- assertEquals(3, rect.top);
- assertEquals(2, rect.left);
- assertEquals(4, rect.right);
- }
}
public void testOnAnimationEnd() {
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 1e23660..2082973 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -3940,6 +3940,89 @@
assertFalse(view2.hasPointerCapture());
}
+ public void testVisibilityAggregated() throws Throwable {
+ final View grandparent = mActivity.findViewById(R.id.viewlayout_root);
+ final View parent = mActivity.findViewById(R.id.aggregate_visibility_parent);
+ final MockView mv = (MockView) mActivity.findViewById(R.id.mock_view_aggregate_visibility);
+
+ assertEquals(parent, mv.getParent());
+ assertEquals(grandparent, parent.getParent());
+
+ assertTrue(mv.hasCalledOnVisibilityAggregated());
+ assertTrue(mv.getLastAggregatedVisibility());
+
+ final Runnable reset = new Runnable() {
+ @Override
+ public void run() {
+ grandparent.setVisibility(View.VISIBLE);
+ parent.setVisibility(View.VISIBLE);
+ mv.setVisibility(View.VISIBLE);
+ mv.reset();
+ }
+ };
+
+ runTestOnUiThread(reset);
+
+ setVisibilityOnUiThread(parent, View.GONE);
+
+ assertTrue(mv.hasCalledOnVisibilityAggregated());
+ assertFalse(mv.getLastAggregatedVisibility());
+
+ runTestOnUiThread(reset);
+
+ setVisibilityOnUiThread(grandparent, View.GONE);
+
+ assertTrue(mv.hasCalledOnVisibilityAggregated());
+ assertFalse(mv.getLastAggregatedVisibility());
+
+ runTestOnUiThread(reset);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ grandparent.setVisibility(View.GONE);
+ parent.setVisibility(View.GONE);
+ mv.setVisibility(View.VISIBLE);
+
+ grandparent.setVisibility(View.VISIBLE);
+ }
+ });
+
+ assertTrue(mv.hasCalledOnVisibilityAggregated());
+ assertFalse(mv.getLastAggregatedVisibility());
+
+ runTestOnUiThread(reset);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ grandparent.setVisibility(View.GONE);
+ parent.setVisibility(View.INVISIBLE);
+
+ grandparent.setVisibility(View.VISIBLE);
+ }
+ });
+
+ assertTrue(mv.hasCalledOnVisibilityAggregated());
+ assertFalse(mv.getLastAggregatedVisibility());
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ parent.setVisibility(View.VISIBLE);
+ }
+ });
+
+ assertTrue(mv.getLastAggregatedVisibility());
+ }
+
+ private void setVisibilityOnUiThread(final View view, int visibility) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ view.setVisibility(visibility);
+ }
+ });
+ }
+
private static class MockViewGroup extends ViewGroup {
boolean isStartActionModeForChildCalled = false;
int startActionModeForChildType = ActionMode.TYPE_PRIMARY;
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java
index dd7de51..3e071b6 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java
@@ -25,7 +25,6 @@
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.os.Parcel;
-import android.os.storage.StorageManager;
import android.test.AndroidTestCase;
import android.util.Printer;
import android.view.inputmethod.InputMethod;
@@ -244,10 +243,6 @@
return;
}
- if (!StorageManager.isFileEncryptedNativeOrEmulated()) {
- return;
- }
-
final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
final List<InputMethodInfo> imis = imm.getInputMethodList();
boolean hasEncryptionAwareInputMethod = false;
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index eb468dd..3a09f77 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -23,7 +23,12 @@
LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctsdeviceutillegacy ctstestserver ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil \
+ ctsdeviceutillegacy \
+ ctstestserver \
+ ctstestrunner \
+ platform-test-annotations
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
index cca7e35..4f89ec1 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
@@ -17,6 +17,7 @@
package android.webkit.cts;
import android.cts.util.NullWebViewUtils;
+import android.platform.test.annotations.Presubmit;
import android.test.ActivityInstrumentationTestCase2;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
@@ -56,6 +57,7 @@
assertFalse(mCookieManager.hasCookies());
}
+ @Presubmit
public void testDomain() {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
index 6768b6f..a4ebaca 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.cts.util.NullWebViewUtils;
import android.cts.util.PollingCheck;
+import android.os.StrictMode;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.util.Log;
@@ -89,4 +90,20 @@
assertEquals("42", m.group(1)); // value got incremented
}
+ @UiThreadTest
+ public void testStrictModeNotViolatedOnStartup() throws Throwable {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ StrictMode.ThreadPolicy testPolicy = new StrictMode.ThreadPolicy.Builder()
+ .detectDiskReads()
+ .penaltyLog()
+ .penaltyDeath()
+ .build();
+ StrictMode.setThreadPolicy(testPolicy);
+ try {
+ mActivity.createAndAttachWebView();
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
}
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index c5c3de3..96f10fc 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -21,7 +21,12 @@
# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES += mockito-target android-common ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += \
+ mockito-target \
+ android-common \
+ ctsdeviceutil \
+ ctstestrunner \
+ platform-test-annotations
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/tests/widget/AndroidTest.xml b/tests/tests/widget/AndroidTest.xml
index d943b85..ed7742a 100644
--- a/tests/tests/widget/AndroidTest.xml
+++ b/tests/tests/widget/AndroidTest.xml
@@ -21,6 +21,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.widget.cts" />
- <option name="runtime-hint" value="3m" />
+ <option name="runtime-hint" value="11m55s" />
</test>
</configuration>
diff --git a/tests/tests/widget/res/layout/popup_window_item.xml b/tests/tests/widget/res/layout/popup_window_item.xml
new file mode 100644
index 0000000..b53fd22
--- /dev/null
+++ b/tests/tests/widget/res/layout/popup_window_item.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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/popup_row_height"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
diff --git a/tests/tests/widget/res/layout/popupwindow.xml b/tests/tests/widget/res/layout/popupwindow.xml
index 7746da8..d84770d 100644
--- a/tests/tests/widget/res/layout/popupwindow.xml
+++ b/tests/tests/widget/res/layout/popupwindow.xml
@@ -20,29 +20,37 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <View android:id="@+id/anchor_upper"
+ <android.widget.cts.MockViewForListPopupWindow
+ 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"
android:layout_width="10dp"
- android:layout_height="10dp"
+ android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="#0f0" />
<View android:id="@+id/anchor_middle_left"
- android:layout_width="10dp"
+ android:layout_width="30dp"
android:layout_height="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="#00f" />
<View android:id="@+id/anchor_middle_right"
- android:layout_width="10dp"
+ android:layout_width="30dp"
android:layout_height="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
diff --git a/tests/tests/widget/res/layout/tabhost_custom.xml b/tests/tests/widget/res/layout/tabhost_custom.xml
new file mode 100644
index 0000000..5308a18
--- /dev/null
+++ b/tests/tests/widget/res/layout/tabhost_custom.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<TabWidget
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="68dip"
+ android:tabStripEnabled="false"
+ android:tabStripLeft="@drawable/icon_red"
+ android:tabStripRight="@drawable/icon_green" />
diff --git a/tests/tests/widget/res/layout/tabhost_layout.xml b/tests/tests/widget/res/layout/tabhost_layout.xml
index 1bae57a..de766f9 100644
--- a/tests/tests/widget/res/layout/tabhost_layout.xml
+++ b/tests/tests/widget/res/layout/tabhost_layout.xml
@@ -24,8 +24,7 @@
android:layout_height="68dip"
android:paddingLeft="1dip"
android:paddingRight="1dip"
- android:paddingTop="4dip"
- />
+ android:paddingTop="4dip" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/tests/tests/widget/res/menu/popup_menu.xml b/tests/tests/widget/res/menu/popup_menu.xml
new file mode 100644
index 0000000..f50efc5
--- /dev/null
+++ b/tests/tests/widget/res/menu/popup_menu.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 Google Inc.
+
+ 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/action_highlight"
+ android:title="@string/popup_menu_highlight" />
+ <item android:id="@+id/action_edit"
+ android:title="@string/popup_menu_edit" />
+ <item android:id="@+id/action_delete"
+ android:title="@string/popup_menu_delete" />
+ <item android:id="@+id/action_ignore"
+ android:title="@string/popup_menu_ignore" />
+ <item android:id="@+id/action_share"
+ android:title="@string/popup_menu_share">
+ <menu>
+ <item android:id="@+id/action_share_email"
+ android:title="@string/popup_menu_share_email" />
+ <item android:id="@+id/action_share_circles"
+ android:title="@string/popup_menu_share_circles" />
+ </menu>
+ </item>
+ <item android:id="@+id/action_print"
+ android:title="@string/popup_menu_print" />
+</menu>
diff --git a/tests/tests/widget/res/transition/custom_transition.xml b/tests/tests/widget/res/transition/custom_transition.xml
new file mode 100644
index 0000000..cb8ea5c
--- /dev/null
+++ b/tests/tests/widget/res/transition/custom_transition.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.
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android"
+ class="android.widget.cts.PopupWindowTest$CustomTransition"
+ android:duration="250" />
diff --git a/tests/tests/widget/res/values/dimens.xml b/tests/tests/widget/res/values/dimens.xml
new file mode 100644
index 0000000..3690039
--- /dev/null
+++ b/tests/tests/widget/res/values/dimens.xml
@@ -0,0 +1,18 @@
+<?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>
+ <dimen name="popup_row_height">48dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/widget/res/values/strings.xml b/tests/tests/widget/res/values/strings.xml
index 51d8708..d889772 100644
--- a/tests/tests/widget/res/values/strings.xml
+++ b/tests/tests/widget/res/values/strings.xml
@@ -177,4 +177,14 @@
text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
I think so, so how about double this string, like copy and paste! </string>
<string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
+
+ <string name="popup_show">Show popup</string>
+ <string name="popup_menu_highlight">Highlight</string>
+ <string name="popup_menu_edit">Edit</string>
+ <string name="popup_menu_delete">Delete</string>
+ <string name="popup_menu_ignore">Ignore</string>
+ <string name="popup_menu_share">Share</string>
+ <string name="popup_menu_share_email">Via email</string>
+ <string name="popup_menu_share_circles">To my circles</string>
+ <string name="popup_menu_print">Print</string>
</resources>
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index 81925cc..da22652 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -35,6 +35,18 @@
<item name="type16">Typed Value!</item>
</style>
+ <style name="PopupWindow" parent="@android:style/Widget.Material.ListPopupWindow" />
+
+ <style name="PopupWindow.NullTransitions">
+ <item name="android:popupEnterTransition">@null</item>
+ <item name="android:popupExitTransition">@null</item>
+ </style>
+
+ <style name="PopupWindow.CustomTransitions">
+ <item name="android:popupEnterTransition">@transition/custom_transition</item>
+ <item name="android:popupExitTransition">@transition/custom_transition</item>
+ </style>
+
<style name="TextViewWithoutColorAndAppearance">
<item name="android:textSize">18sp</item>
</style>
@@ -169,4 +181,11 @@
<item name="android:windowSwipeToDismiss">false</item>
</style>
+ <style name="PopupEmptyStyle" />
+
+ <style name="TabWidgetCustomStyle" parent="android:Widget.TabWidget">
+ <item name="android:tabStripEnabled">false</item>
+ <item name="android:tabStripLeft">@drawable/icon_green</item>
+ <item name="android:tabStripRight">@drawable/icon_red</item>
+ </style>
</resources>
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
index 1fc0cef..bdda79a 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
@@ -16,22 +16,19 @@
package android.widget.cts;
-import android.content.res.ColorStateList;
-import android.cts.util.WidgetTestUtils;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuff;
-
-import android.widget.cts.R;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.cts.util.PollingCheck;
+import android.cts.util.WidgetTestUtils;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.BitmapDrawable;
@@ -47,6 +44,8 @@
import android.widget.FrameLayout.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.widget.cts.R;
+import android.widget.cts.util.ViewTestUtils;
import java.io.IOException;
@@ -88,12 +87,8 @@
assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth());
assertNull(mFrameLayout.getForeground());
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- mFrameLayout.setForeground(foreground);
- }
- });
- mInstrumentation.waitForIdleSync();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
+ () -> mFrameLayout.setForeground(foreground));
assertSame(foreground, mFrameLayout.getForeground());
// check the default gravity FILL, it completely fills its container
assertTrue(foreground.isVisible());
@@ -108,18 +103,16 @@
assertEquals(mFrameLayout.getWidth(), rect.right - rect.left);
// should get a new foreground again, because former foreground has been stretched
- final BitmapDrawable newForeground
- = (BitmapDrawable) mActivity.getResources().getDrawable(R.drawable.size_48x48);
+ final BitmapDrawable newForeground =
+ (BitmapDrawable) mActivity.getResources().getDrawable(R.drawable.size_48x48);
compareScaledPixels(48, newForeground.getIntrinsicHeight());
compareScaledPixels(48, newForeground.getIntrinsicWidth());
assertTrue(mFrameLayout.getHeight() > newForeground.getIntrinsicHeight());
assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth());
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- mFrameLayout.setForeground(newForeground);
- mFrameLayout.setForegroundGravity(Gravity.CENTER);
- }
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
+ mFrameLayout.setForeground(newForeground);
+ mFrameLayout.setForegroundGravity(Gravity.CENTER);
});
mInstrumentation.waitForIdleSync();
assertSame(newForeground, mFrameLayout.getForeground());
@@ -132,24 +125,19 @@
}
public void testGatherTransparentRegion() {
- final LinearLayout container
- = (LinearLayout) mActivity.findViewById(R.id.framelayout_container);
+ final LinearLayout container =
+ (LinearLayout) mActivity.findViewById(R.id.framelayout_container);
final Drawable foreground = mActivity.getResources().getDrawable(R.drawable.size_48x48);
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- mFrameLayout.setForeground(foreground);
- mFrameLayout.setForegroundGravity(Gravity.CENTER);
- }
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
+ mFrameLayout.setForeground(foreground);
+ mFrameLayout.setForegroundGravity(Gravity.CENTER);
});
mInstrumentation.waitForIdleSync();
Region region = new Region(foreground.getBounds());
assertTrue(mFrameLayout.gatherTransparentRegion(region));
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- container.requestTransparentRegion(mFrameLayout);
- }
- });
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
+ () -> container.requestTransparentRegion(mFrameLayout));
mInstrumentation.waitForIdleSync();
region = new Region(foreground.getBounds());
assertTrue(mFrameLayout.gatherTransparentRegion(region));
@@ -168,11 +156,9 @@
assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth());
// measureAll is false and text view is GONE, text view will NOT be measured
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- textView.setVisibility(View.GONE);
- frameLayout.requestLayout();
- }
+ mActivity.runOnUiThread(() -> {
+ textView.setVisibility(View.GONE);
+ frameLayout.requestLayout();
});
mInstrumentation.waitForIdleSync();
assertFalse(frameLayout.getConsiderGoneChildrenWhenMeasuring());
@@ -183,11 +169,9 @@
assertEquals(button.getMeasuredWidth(), frameLayout.getMeasuredWidth());
// measureAll is true and text view is GONE, text view will be measured
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- frameLayout.setMeasureAllChildren(true);
- frameLayout.requestLayout();
- }
+ mActivity.runOnUiThread(() -> {
+ frameLayout.setMeasureAllChildren(true);
+ frameLayout.requestLayout();
});
mInstrumentation.waitForIdleSync();
assertTrue(frameLayout.getConsiderGoneChildrenWhenMeasuring());
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 76fa782..895184d 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,24 +16,24 @@
package android.widget.cts;
-import android.graphics.Color;
-import android.view.View;
-import android.view.ViewTreeObserver;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
import android.content.Context;
+import android.graphics.Color;
import android.test.ActivityInstrumentationTestCase;
import android.test.ViewAsserts;
import android.util.AttributeSet;
import android.util.Xml;
+import android.view.View;
+import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-import android.widget.LinearLayout.LayoutParams;
+import android.view.ViewTreeObserver;
import android.widget.AbsoluteLayout;
import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;
-
import android.widget.cts.R;
import java.util.concurrent.CountDownLatch;
@@ -177,6 +177,54 @@
assertEquals(Math.ceil(parentWidth * 0.3), weight03.getWidth(), 1.0);
}
+ public void testWeightDistribution() {
+ LinearLayout layout = new LinearLayout(mActivity);
+ for (int i = 0; i < 3; i++) {
+ layout.addView(new View(mActivity), new LayoutParams(0, 0, 1));
+ }
+
+ int size = 100;
+ int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < 3; i++) {
+ View child = layout.getChildAt(i);
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.height = 0;
+ lp.width = LayoutParams.MATCH_PARENT;
+ child.setLayoutParams(lp);
+ }
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.measure(spec, spec);
+ layout.layout(0, 0, size, size);
+ assertEquals(100, layout.getWidth());
+ assertEquals(100, layout.getChildAt(0).getWidth());
+ assertEquals(100, layout.getChildAt(1).getWidth());
+ assertEquals(100, layout.getChildAt(2).getWidth());
+ assertEquals(100, layout.getHeight());
+ assertEquals(33, layout.getChildAt(0).getHeight());
+ assertEquals(33, layout.getChildAt(1).getHeight());
+ assertEquals(34, layout.getChildAt(2).getHeight());
+
+ for (int i = 0; i < 3; i++) {
+ View child = layout.getChildAt(i);
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.height = LayoutParams.MATCH_PARENT;
+ lp.width = 0;
+ child.setLayoutParams(lp);
+ }
+ layout.setOrientation(LinearLayout.HORIZONTAL);
+ layout.measure(spec, spec);
+ layout.layout(0, 0, size, size);
+ assertEquals(100, layout.getWidth());
+ assertEquals(33, layout.getChildAt(0).getWidth());
+ assertEquals(33, layout.getChildAt(1).getWidth());
+ assertEquals(34, layout.getChildAt(2).getWidth());
+ assertEquals(100, layout.getHeight());
+ assertEquals(100, layout.getChildAt(0).getHeight());
+ assertEquals(100, layout.getChildAt(1).getHeight());
+ assertEquals(100, layout.getChildAt(2).getHeight());
+ }
+
public void testGenerateLayoutParams() {
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(320, 240);
MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext);
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index da5b9fe..abe7848 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -23,11 +23,13 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.Display;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -104,6 +106,11 @@
new ListPopupWindow(mActivity, null, 0, android.R.style.Widget_Material_ListPopupWindow);
}
+ public void noDefaultVisibility() {
+ mPopupWindow = new ListPopupWindow(mActivity);
+ assertFalse(mPopupWindow.isShowing());
+ }
+
public void testAccessBackground() {
mPopupWindowBuilder = new Builder();
mPopupWindowBuilder.show();
@@ -280,8 +287,6 @@
public void testDismiss() {
mPopupWindowBuilder = new Builder();
- assertFalse(mPopupWindow.isShowing());
-
mPopupWindowBuilder.show();
assertTrue(mPopupWindow.isShowing());
@@ -510,6 +515,7 @@
assertTrue(lastChildOnScreenXY[1] + lastListChild.getHeight() <= promptViewOnScreenXY[1]);
}
+ @Presubmit
public void testAccessSelection() throws Throwable {
mPopupWindowBuilder = new Builder().withItemSelectedListener();
mPopupWindowBuilder.show();
@@ -569,6 +575,204 @@
verifyNoMoreInteractions(mPopupWindowBuilder.mOnItemSelectedListener);
}
+ public void testNoDefaultDismissalWithBackButton() throws Throwable {
+ mPopupWindowBuilder = new Builder().withDismissListener();
+ mPopupWindowBuilder.show();
+
+ // Send BACK key event. As we don't have any custom code that dismisses ListPopupWindow,
+ // and ListPopupWindow doesn't track that system-level key event on its own, ListPopupWindow
+ // should stay visible
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ verify(mPopupWindowBuilder.mOnDismissListener, never()).onDismiss();
+ assertTrue(mPopupWindow.isShowing());
+ }
+
+ public void testCustomDismissalWithBackButton() throws Throwable {
+ mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
+ .withDismissListener();
+ mPopupWindowBuilder.show();
+
+ // "Point" our custom extension of EditText to our ListPopupWindow
+ final MockViewForListPopupWindow anchor =
+ (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
+ anchor.wireTo(mPopupWindow);
+ // Request focus on our EditText
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ anchor.requestFocus();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(anchor.isFocused());
+
+ // Send BACK key event. As our custom extension of EditText calls
+ // ListPopupWindow.onKeyPreIme, the end result should be the dismissal of the
+ // ListPopupWindow
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
+ assertFalse(mPopupWindow.isShowing());
+ }
+
+ public void testListSelectionWithDPad() throws Throwable {
+ mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
+ .withDismissListener().withItemSelectedListener();
+ mPopupWindowBuilder.show();
+
+ // "Point" our custom extension of EditText to our ListPopupWindow
+ final MockViewForListPopupWindow anchor =
+ (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
+ anchor.wireTo(mPopupWindow);
+ // Request focus on our EditText
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ anchor.requestFocus();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(anchor.isFocused());
+
+ // Select entry #1 in the popup list
+ final ListView listView = mPopupWindow.getListView();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, new Runnable() {
+ public void run() {
+ mPopupWindow.setSelection(1);
+ }
+ });
+ verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
+ any(AdapterView.class), any(View.class), eq(1), eq(1L));
+
+ // Send DPAD_DOWN key event. As our custom extension of EditText calls
+ // ListPopupWindow.onKeyDown and onKeyUp, the end result should be transfer of selection
+ // down one row
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ mInstrumentation.waitForIdleSync();
+
+ // At this point we expect that item #2 was selected
+ verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
+ any(AdapterView.class), any(View.class), eq(2), eq(2L));
+
+ // Send a DPAD_UP key event. As our custom extension of EditText calls
+ // ListPopupWindow.onKeyDown and onKeyUp, the end result should be transfer of selection
+ // up one row
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
+ mInstrumentation.waitForIdleSync();
+
+ // At this point we expect that item #1 was selected
+ verify(mPopupWindowBuilder.mOnItemSelectedListener, times(2)).onItemSelected(
+ any(AdapterView.class), any(View.class), eq(1), eq(1L));
+
+ // Send one more DPAD_UP key event. As our custom extension of EditText calls
+ // ListPopupWindow.onKeyDown and onKeyUp, the end result should be transfer of selection
+ // up one more row
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
+ mInstrumentation.waitForIdleSync();
+
+ // At this point we expect that item #0 was selected
+ verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
+ any(AdapterView.class), any(View.class), eq(0), eq(0L));
+
+ // Send ENTER key event. As our custom extension of EditText calls
+ // ListPopupWindow.onKeyDown and onKeyUp, the end result should be dismissal of
+ // the popup window
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
+ mInstrumentation.waitForIdleSync();
+
+ verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
+ assertFalse(mPopupWindow.isShowing());
+
+ verifyNoMoreInteractions(mPopupWindowBuilder.mOnItemSelectedListener);
+ verifyNoMoreInteractions(mPopupWindowBuilder.mOnDismissListener);
+ }
+
+ /**
+ * Emulates a drag-down gestures by injecting ACTION events with {@link Instrumentation}.
+ */
+ private void emulateDragDownGesture(int emulatedX, int emulatedStartY, int swipeAmount) {
+ // The logic below uses Instrumentation to emulate a swipe / drag gesture to bring up
+ // the popup content.
+
+ // Inject DOWN event
+ long downTime = SystemClock.uptimeMillis();
+ MotionEvent eventDown = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_DOWN, emulatedX, emulatedStartY, 1);
+ mInstrumentation.sendPointerSync(eventDown);
+
+ // Inject a sequence of MOVE events that emulate a "swipe down" gesture
+ for (int i = 0; i < 10; i++) {
+ long moveTime = SystemClock.uptimeMillis();
+ final int moveY = emulatedStartY + swipeAmount * i / 10;
+ MotionEvent eventMove = MotionEvent.obtain(
+ moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedX, moveY, 1);
+ mInstrumentation.sendPointerSync(eventMove);
+ // sleep for a bit to emulate a 200ms swipe
+ SystemClock.sleep(20);
+ }
+
+ // Inject UP event
+ long upTime = SystemClock.uptimeMillis();
+ MotionEvent eventUp = MotionEvent.obtain(
+ upTime, upTime, MotionEvent.ACTION_UP, emulatedX, emulatedStartY + swipeAmount, 1);
+ mInstrumentation.sendPointerSync(eventUp);
+
+ // Wait for the system to process all events in the queue
+ mInstrumentation.waitForIdleSync();
+ }
+
+ public void testCreateOnDragListener() throws Throwable {
+ // In this test we want precise control over the height of the popup content since
+ // we need to know by how much to swipe down to end the emulated gesture over the
+ // specific item in the popup. This is why we're using a popup style that removes
+ // all decoration around the popup content, as well as our own row layout with known
+ // height.
+ mPopupWindowBuilder = new Builder()
+ .withPopupStyleAttr(R.style.PopupEmptyStyle)
+ .withContentRowLayoutId(R.layout.popup_window_item)
+ .withItemClickListener().withDismissListener();
+
+ // Configure ListPopupWindow without showing it
+ mPopupWindowBuilder.configure();
+
+ // Get the anchor view and configure it with ListPopupWindow's drag-to-open listener
+ final View anchor = mActivity.findViewById(mPopupWindowBuilder.mAnchorId);
+ View.OnTouchListener dragListener = mPopupWindow.createDragToOpenListener(anchor);
+ anchor.setOnTouchListener(dragListener);
+ // And also configure it to show the popup window on click
+ anchor.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPopupWindow.show();
+ }
+ });
+
+ // Get the height of a row item in our popup window
+ final int popupRowHeight = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.popup_row_height);
+
+ final int[] anchorOnScreenXY = new int[2];
+ anchor.getLocationOnScreen(anchorOnScreenXY);
+
+ // Compute the start coordinates of a downward swipe and the amount of swipe. We'll
+ // be swiping by twice the row height. That, combined with the swipe originating in the
+ // center of the anchor should result in clicking the second row in the popup.
+ int emulatedX = anchorOnScreenXY[0] + anchor.getWidth() / 2;
+ int emulatedStartY = anchorOnScreenXY[1] + anchor.getHeight() / 2;
+ int swipeAmount = 2 * popupRowHeight;
+
+ // Emulate drag-down gesture with a sequence of motion events
+ emulateDragDownGesture(emulatedX, emulatedStartY, swipeAmount);
+
+ // We expect the swipe / drag gesture to result in clicking the second item in our list.
+ verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
+ any(AdapterView.class), any(View.class), eq(1), eq(1L));
+ // Since our item click listener calls dismiss() on the popup, we expect the popup to not
+ // be showing
+ assertFalse(mPopupWindow.isShowing());
+ // At this point our popup should have notified its dismiss listener
+ verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
+ }
+
/**
* Inner helper class to configure an instance of <code>ListPopupWindow</code> for the
* specific test. The main reason for its existence is that once a popup window is shown
@@ -585,10 +789,15 @@
private int mHorizontalOffset;
private int mVerticalOffset;
private int mDropDownGravity;
+ private int mAnchorId = R.id.anchor_upper;
+ private int mContentRowLayoutId = android.R.layout.simple_list_item_1;
private boolean mHasWindowLayoutType;
private int mWindowLayoutType;
+ private boolean mUseCustomPopupStyle;
+ private int mPopupStyleAttr;
+
private View mPromptView;
private int mPromptPosition;
@@ -597,7 +806,22 @@
private PopupWindow.OnDismissListener mOnDismissListener;
public Builder() {
- mPopupWindow = new ListPopupWindow(mActivity);
+ }
+
+ public Builder withAnchor(int anchorId) {
+ mAnchorId = anchorId;
+ return this;
+ }
+
+ public Builder withContentRowLayoutId(int contentRowLayoutId) {
+ mContentRowLayoutId = contentRowLayoutId;
+ return this;
+ }
+
+ public Builder withPopupStyleAttr(int popupStyleAttr) {
+ mUseCustomPopupStyle = true;
+ mPopupStyleAttr = popupStyleAttr;
+ return this;
}
public Builder ignoreContentWidth() {
@@ -687,7 +911,12 @@
return width;
}
- private void show() {
+ private void configure() {
+ if (mUseCustomPopupStyle) {
+ mPopupWindow = new ListPopupWindow(mActivity, null, mPopupStyleAttr, 0);
+ } else {
+ mPopupWindow = new ListPopupWindow(mActivity);
+ }
final String[] POPUP_CONTENT =
new String[]{"Alice", "Bob", "Charlie", "Deirdre", "El"};
final BaseAdapter listPopupAdapter = new BaseAdapter() {
@@ -714,7 +943,7 @@
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(mActivity).inflate(
- android.R.layout.simple_list_item_1, parent, false);
+ mContentRowLayoutId, parent, false);
ViewHolder viewHolder = new ViewHolder();
viewHolder.title = (TextView) convertView.findViewById(android.R.id.text1);
convertView.setTag(viewHolder);
@@ -727,7 +956,7 @@
};
mPopupWindow.setAdapter(listPopupAdapter);
- mPopupWindow.setAnchorView(mActivity.findViewById(R.id.anchor_upper));
+ mPopupWindow.setAnchorView(mActivity.findViewById(mAnchorId));
// The following mock listeners have to be set before the call to show() as
// they are set on the internally constructed drop down.
@@ -780,6 +1009,10 @@
mPopupWindow.setPromptPosition(mPromptPosition);
mPopupWindow.setPromptView(mPromptView);
}
+ }
+
+ private void show() {
+ configure();
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
diff --git a/tests/tests/widget/src/android/widget/cts/MockViewForListPopupWindow.java b/tests/tests/widget/src/android/widget/cts/MockViewForListPopupWindow.java
new file mode 100644
index 0000000..dc6cfc6
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/MockViewForListPopupWindow.java
@@ -0,0 +1,64 @@
+/*
+ * 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.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.ListPopupWindow;
+
+public class MockViewForListPopupWindow extends EditText {
+ private ListPopupWindow mListPopupWindow;
+
+ public MockViewForListPopupWindow(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MockViewForListPopupWindow(Context context) {
+ super(context);
+ }
+
+ public void wireTo(ListPopupWindow listPopupWindow) {
+ mListPopupWindow = listPopupWindow;
+ }
+
+ @Override
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (mListPopupWindow != null) {
+ return mListPopupWindow.onKeyPreIme(keyCode, event);
+ }
+ return super.onKeyPreIme(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mListPopupWindow != null) {
+ return mListPopupWindow.onKeyDown(keyCode, event);
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (mListPopupWindow != null) {
+ return mListPopupWindow.onKeyUp(keyCode, event);
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+}
+
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 206b794..2339101 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -16,21 +16,32 @@
package android.widget.cts;
-import static org.mockito.Mockito.*;
-
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;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SubMenu;
+import android.view.View;
import android.widget.PopupMenu;
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
+@SmallTest
public class PopupMenuTest extends
ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
private Instrumentation mInstrumentation;
private Activity mActivity;
+ private Builder mBuilder;
+ private PopupMenu mPopupMenu;
+
public PopupMenuTest() {
super("android.widget.cts", MockPopupWindowCtsActivity.class);
}
@@ -42,43 +53,382 @@
mActivity = getActivity();
}
- public void testAccessGravity() {
- PopupMenu popupMenu = new PopupMenu(mActivity,
- mActivity.findViewById(R.id.anchor_middle_left));
- assertEquals(Gravity.NO_GRAVITY, popupMenu.getGravity());
-
- popupMenu.setGravity(Gravity.TOP);
- assertEquals(Gravity.TOP, popupMenu.getGravity());
+ @Override
+ protected void tearDown() throws Exception {
+ if (mPopupMenu != null) {
+ try {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mPopupMenu.dismiss();
+ }
+ });
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ super.tearDown();
}
- public void testOnDismissListener() {
- final PopupMenu popupMenu = new PopupMenu(mActivity,
- mActivity.findViewById(R.id.anchor_middle_left));
- PopupMenu.OnDismissListener listener = mock(PopupMenu.OnDismissListener.class);
- popupMenu.setOnDismissListener(listener);
+ private void verifyMenuContent() {
+ final Menu menu = mPopupMenu.getMenu();
+ assertEquals(6, menu.size());
+ assertEquals(R.id.action_highlight, menu.getItem(0).getItemId());
+ assertEquals(R.id.action_edit, menu.getItem(1).getItemId());
+ assertEquals(R.id.action_delete, menu.getItem(2).getItemId());
+ assertEquals(R.id.action_ignore, menu.getItem(3).getItemId());
+ assertEquals(R.id.action_share, menu.getItem(4).getItemId());
+ assertEquals(R.id.action_print, menu.getItem(5).getItemId());
- mInstrumentation.runOnMainSync(new Runnable() {
- public void run() {
- popupMenu.show();
- }
- });
- mInstrumentation.waitForIdleSync();
- verify(listener, never()).onDismiss(popupMenu);
-
- mInstrumentation.runOnMainSync(new Runnable() {
- public void run() {
- popupMenu.dismiss();
- }
- });
- mInstrumentation.waitForIdleSync();
- verify(listener, times(1)).onDismiss(popupMenu);
-
- mInstrumentation.runOnMainSync(new Runnable() {
- public void run() {
- popupMenu.dismiss();
- }
- });
- mInstrumentation.waitForIdleSync();
- verify(listener, times(1)).onDismiss(popupMenu);
+ final SubMenu shareSubMenu = menu.getItem(4).getSubMenu();
+ assertNotNull(shareSubMenu);
+ assertEquals(2, shareSubMenu.size());
+ assertEquals(R.id.action_share_email, shareSubMenu.getItem(0).getItemId());
+ assertEquals(R.id.action_share_circles, shareSubMenu.getItem(1).getItemId());
}
-}
+
+ public void testPopulateViaInflater() throws Throwable {
+ mBuilder = new Builder().inflateWithInflater(true);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ verifyMenuContent();
+ }
+
+ public void testDirectPopulate() throws Throwable {
+ mBuilder = new Builder().inflateWithInflater(false);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ verifyMenuContent();
+ }
+
+ public void testAccessGravity() throws Throwable {
+ mBuilder = new Builder();
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+
+ assertEquals(Gravity.NO_GRAVITY, mPopupMenu.getGravity());
+ mPopupMenu.setGravity(Gravity.TOP);
+ assertEquals(Gravity.TOP, mPopupMenu.getGravity());
+ }
+
+ public void testConstructorWithGravity() throws Throwable {
+ mBuilder = new Builder().withGravity(Gravity.TOP);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+
+ assertEquals(Gravity.TOP, mPopupMenu.getGravity());
+ }
+
+ public void testDismissalViaAPI() throws Throwable {
+ mBuilder = new Builder().withDismissListener();
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+ verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mPopupMenu.dismiss();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mPopupMenu.dismiss();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ // Shouldn't have any more interactions with our dismiss listener since the menu was
+ // already dismissed when we called dismiss()
+ verifyNoMoreInteractions(mBuilder.mOnDismissListener);
+ }
+
+ public void testNestedDismissalViaAPI() throws Throwable {
+ // Use empty popup style to remove all transitions from the popup. That way we don't
+ // need to synchronize with the popup window enter transition before proceeding to
+ // "click" a submenu item.
+ mBuilder = new Builder().withDismissListener()
+ .withPopupStyleAttr(R.style.PopupEmptyStyle);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
+ performIdentifierAction(R.id.action_share_email, 0);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mPopupMenu.dismiss();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mPopupMenu.dismiss();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ // Shouldn't have any more interactions with our dismiss listener since the menu was
+ // already dismissed when we called dismiss()
+ verifyNoMoreInteractions(mBuilder.mOnDismissListener);
+ }
+
+ public void testDismissalViaTouch() throws Throwable {
+ // Use empty popup style to remove all transitions from the popup. That way we don't
+ // need to synchronize with the popup window enter transition before proceeding to
+ // emulate a click outside the popup window bounds.
+ mBuilder = new Builder().withDismissListener()
+ .withPopupStyleAttr(R.style.PopupEmptyStyle);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // Determine the location of the anchor on the screen so that we can emulate
+ // a tap outside of the popup bounds to dismiss the popup
+ final int[] anchorOnScreenXY = new int[2];
+ mBuilder.mAnchor.getLocationOnScreen(anchorOnScreenXY);
+
+ int emulatedTapX = anchorOnScreenXY[0] + 10;
+ int emulatedTapY = anchorOnScreenXY[1] - 20;
+
+ // The logic below uses Instrumentation to emulate a tap outside the bounds of the
+ // displayed popup menu. This tap is then treated by the framework to be "split" as
+ // the ACTION_OUTSIDE for the popup itself, as well as DOWN / MOVE / UP for the underlying
+ // view root if the popup is not modal.
+ // It is not correct to emulate these two sequences separately in the test, as it
+ // wouldn't emulate the user-facing interaction for this test. Note that usage
+ // of Instrumentation is necessary here since Espresso's actions operate at the level
+ // of view or data. Also, we don't want to use View.dispatchTouchEvent directly as
+ // that would require emulation of two separate sequences as well.
+
+ // Inject DOWN event
+ long downTime = SystemClock.uptimeMillis();
+ MotionEvent eventDown = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
+ mInstrumentation.sendPointerSync(eventDown);
+
+ // Inject MOVE event
+ long moveTime = SystemClock.uptimeMillis();
+ MotionEvent eventMove = MotionEvent.obtain(
+ moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
+ mInstrumentation.sendPointerSync(eventMove);
+
+ // Inject UP event
+ long upTime = SystemClock.uptimeMillis();
+ MotionEvent eventUp = MotionEvent.obtain(
+ upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
+ mInstrumentation.sendPointerSync(eventUp);
+
+ // Wait for the system to process all events in the queue
+ mInstrumentation.waitForIdleSync();
+
+ // At this point our popup should have notified its dismiss listener
+ verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
+ }
+
+ public void testSimpleMenuItemClickViaAPI() throws Throwable {
+ mBuilder = new Builder().withMenuItemClickListener().withDismissListener();
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+
+ // Verify that our menu item click listener hasn't been called yet
+ verify(mBuilder.mOnMenuItemClickListener, never()).onMenuItemClick(any(MenuItem.class));
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mPopupMenu.getMenu().performIdentifierAction(R.id.action_highlight, 0);
+ }
+ });
+
+ // Verify that our menu item click listener has been called with the expected menu item
+ verify(mBuilder.mOnMenuItemClickListener, times(1)).onMenuItemClick(
+ mPopupMenu.getMenu().findItem(R.id.action_highlight));
+
+ // Popup menu should be automatically dismissed on selecting an item
+ verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
+ verifyNoMoreInteractions(mBuilder.mOnDismissListener);
+ }
+
+ public void testSubMenuClickViaAPI() throws Throwable {
+ // Use empty popup style to remove all transitions from the popup. That way we don't
+ // need to synchronize with the popup window enter transition before proceeding to
+ // "click" a submenu item.
+ mBuilder = new Builder().withDismissListener().withMenuItemClickListener()
+ .withPopupStyleAttr(R.style.PopupEmptyStyle);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mBuilder.show();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // Verify that our menu item click listener hasn't been called yet
+ verify(mBuilder.mOnMenuItemClickListener, never()).onMenuItemClick(any(MenuItem.class));
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0);
+ }
+ });
+ // Verify that our menu item click listener has been called on "share" action
+ verify(mBuilder.mOnMenuItemClickListener, times(1)).onMenuItemClick(
+ mPopupMenu.getMenu().findItem(R.id.action_share));
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
+ performIdentifierAction(R.id.action_share_email, 0);
+ }
+ });
+
+ // Verify that out menu item click listener has been called with the expected menu item
+ verify(mBuilder.mOnMenuItemClickListener, times(1)).onMenuItemClick(
+ mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu()
+ .findItem(R.id.action_share_email));
+ verifyNoMoreInteractions(mBuilder.mOnMenuItemClickListener);
+
+ // Popup menu should be automatically dismissed on selecting an item
+ verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
+ verifyNoMoreInteractions(mBuilder.mOnDismissListener);
+ }
+
+ /**
+ * Inner helper class to configure an instance of {@link PopupMenu} for the specific test.
+ * The main reason for its existence is that once a popup menu is shown with the show() method,
+ * most of its configuration APIs are no-ops. This means that we can't add logic that is
+ * specific to a certain test once it's shown and we have a reference to a displayed
+ * {@link PopupMenu}.
+ */
+ public class Builder {
+ private boolean mHasDismissListener;
+ private boolean mHasMenuItemClickListener;
+ private boolean mInflateWithInflater;
+
+ private boolean mUseCustomPopupStyle;
+ private int mPopupStyleAttr = android.R.attr.popupMenuStyle;
+
+ private boolean mUseCustomGravity;
+ private int mGravity = Gravity.NO_GRAVITY;
+
+ private PopupMenu.OnMenuItemClickListener mOnMenuItemClickListener;
+ private PopupMenu.OnDismissListener mOnDismissListener;
+
+ private View mAnchor;
+
+ public Builder withMenuItemClickListener() {
+ mHasMenuItemClickListener = true;
+ return this;
+ }
+
+ public Builder withDismissListener() {
+ mHasDismissListener = true;
+ return this;
+ }
+
+ public Builder inflateWithInflater(boolean inflateWithInflater) {
+ mInflateWithInflater = inflateWithInflater;
+ return this;
+ }
+
+ public Builder withPopupStyleAttr(int popupStyleAttr) {
+ mUseCustomPopupStyle = true;
+ mPopupStyleAttr = popupStyleAttr;
+ return this;
+ }
+
+ public Builder withGravity(int gravity) {
+ mUseCustomGravity = true;
+ mGravity = gravity;
+ return this;
+ }
+
+ private void configure() {
+ mAnchor = mActivity.findViewById(R.id.anchor_middle_left);
+ if (!mUseCustomGravity && !mUseCustomPopupStyle) {
+ mPopupMenu = new PopupMenu(mActivity, mAnchor);
+ } else if (!mUseCustomPopupStyle) {
+ mPopupMenu = new PopupMenu(mActivity, mAnchor, mGravity);
+ } else {
+ mPopupMenu = new PopupMenu(mActivity, mAnchor, Gravity.NO_GRAVITY,
+ mPopupStyleAttr, 0);
+ }
+
+ if (mInflateWithInflater) {
+ final MenuInflater menuInflater = mPopupMenu.getMenuInflater();
+ menuInflater.inflate(R.menu.popup_menu, mPopupMenu.getMenu());
+ } else {
+ mPopupMenu.inflate(R.menu.popup_menu);
+ }
+
+ if (mHasMenuItemClickListener) {
+ // Register a mock listener to be notified when a menu item in our popup menu has
+ // been clicked.
+ mOnMenuItemClickListener = mock(PopupMenu.OnMenuItemClickListener.class);
+ mPopupMenu.setOnMenuItemClickListener(mOnMenuItemClickListener);
+ }
+
+ if (mHasDismissListener) {
+ // Register a mock listener to be notified when our popup menu is dismissed.
+ mOnDismissListener = mock(PopupMenu.OnDismissListener.class);
+ mPopupMenu.setOnDismissListener(mOnDismissListener);
+ }
+ }
+
+ public void show() {
+ configure();
+ // Show the popup menu
+ mPopupMenu.show();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index db67787..7f5f6e7 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -18,6 +18,7 @@
import static org.mockito.Mockito.*;
+import android.util.AttributeSet;
import org.mockito.InOrder;
import android.app.Activity;
@@ -130,6 +131,52 @@
assertTrue(mPopupWindow.isFocusable());
}
+ public void testAccessEnterExitTransitions() {
+ PopupWindow w;
+
+ w = new PopupWindow(mActivity, null, 0, 0);
+ assertNull(w.getEnterTransition());
+ assertNull(w.getExitTransition());
+
+ w = new PopupWindow(mActivity, null, 0, R.style.PopupWindow_NullTransitions);
+ assertNull(w.getEnterTransition());
+ assertNull(w.getExitTransition());
+
+ w = new PopupWindow(mActivity, null, 0, R.style.PopupWindow_CustomTransitions);
+ assertTrue(w.getEnterTransition() instanceof CustomTransition);
+ assertTrue(w.getExitTransition() instanceof CustomTransition);
+
+ Transition enterTransition = new CustomTransition();
+ Transition exitTransition = new CustomTransition();
+ w = new PopupWindow(mActivity, null, 0, 0);
+ w.setEnterTransition(enterTransition);
+ w.setExitTransition(exitTransition);
+ assertEquals(enterTransition, w.getEnterTransition());
+ assertEquals(exitTransition, w.getExitTransition());
+
+ w.setEnterTransition(null);
+ w.setExitTransition(null);
+ assertNull(w.getEnterTransition());
+ assertNull(w.getExitTransition());
+ }
+
+ public static class CustomTransition extends Transition {
+ public CustomTransition() {
+ }
+
+ // This constructor is needed for reflection-based creation of a transition when
+ // the transition is defined in layout XML via attribute.
+ public CustomTransition(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {}
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {}
+ }
+
public void testAccessBackground() {
mPopupWindow = new PopupWindow(mActivity);
diff --git a/tests/tests/widget/src/android/widget/cts/TabHostTest.java b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
index 0544c24..8756687 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHostTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
@@ -16,25 +16,26 @@
package android.widget.cts;
-import android.widget.cts.R;
-
-
import android.app.Activity;
import android.app.ActivityGroup;
import android.content.Intent;
import android.cts.util.WidgetTestUtils;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import android.widget.ListView;
import android.widget.TabHost;
-import android.widget.TextView;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabSpec;
+import android.widget.TextView;
+
+import static org.mockito.Mockito.*;
/**
* Test {@link TabHost}.
*/
+@SmallTest
public class TabHostTest extends ActivityInstrumentationTestCase2<TabHostCtsActivity> {
private static final String TAG_TAB1 = "tab 1";
private static final String TAG_TAB2 = "tab 2";
@@ -182,18 +183,12 @@
assertEquals(0, tabHost.getCurrentTab());
assertNotNull(tabHost.getCurrentView());
- /*
- TODO: Uncomment after fixing clearAllTabs() issue.
- The code below throws a NullPointerException in clearAllTabs(). The method throwing the
- exception is TabWidget.onFocusChange().
-
tabHost.clearAllTabs();
assertEquals(0, tabHost.getTabWidget().getChildCount());
assertEquals(0, tabHost.getTabContentView().getChildCount());
assertEquals(-1, tabHost.getCurrentTab());
assertNull(tabHost.getCurrentView());
- */
}
public void testGetTabWidget() {
@@ -334,25 +329,23 @@
TabHost tabHost = mActivity.getTabHost();
// add a tab, and change current tab to the new tab
- MockOnTabChangeListener listener = new MockOnTabChangeListener();
- tabHost.setOnTabChangedListener(listener);
+ OnTabChangeListener mockTabChangeListener = mock(OnTabChangeListener.class);
+ tabHost.setOnTabChangedListener(mockTabChangeListener);
TabSpec tabSpec = tabHost.newTabSpec(TAG_TAB2);
tabSpec.setIndicator(TAG_TAB2);
tabSpec.setContent(new MyTabContentFactoryList());
tabHost.addTab(tabSpec);
tabHost.setCurrentTab(1);
- assertTrue(listener.hasCalledOnTabChanged());
+ verify(mockTabChangeListener, times(1)).onTabChanged(TAG_TAB2);
// change current tab to the first one
- listener.reset();
tabHost.setCurrentTab(0);
- assertTrue(listener.hasCalledOnTabChanged());
+ verify(mockTabChangeListener, times(1)).onTabChanged(TabHostCtsActivity.INITIAL_TAB_TAG);
// set the same tab
- listener.reset();
tabHost.setCurrentTab(0);
- assertFalse(listener.hasCalledOnTabChanged());
+ verifyNoMoreInteractions(mockTabChangeListener);
}
@UiThreadTest
@@ -387,21 +380,4 @@
return lv;
}
}
-
- private class MockOnTabChangeListener implements OnTabChangeListener {
- private boolean mCalledOnTabChanged = false;
-
- boolean hasCalledOnTabChanged() {
- return mCalledOnTabChanged;
- }
-
- void reset() {
- mCalledOnTabChanged = false;
- }
-
- public void onTabChanged(String tabId) {
- mCalledOnTabChanged = true;
- }
- }
-
}
diff --git a/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java b/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
index f44117a..58fbf46 100644
--- a/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
@@ -19,19 +19,24 @@
import android.app.Activity;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TabWidget;
import android.widget.TextView;
-import android.widget.LinearLayout.LayoutParams;
+import android.widget.cts.util.TestUtils;
/**
* Test {@link TabWidget}.
*/
+@SmallTest
public class TabWidgetTest extends ActivityInstrumentationTestCase2<TabHostCtsActivity> {
private Activity mActivity;
@@ -53,6 +58,76 @@
new TabWidget(mActivity, null, 0);
}
+ public void testConstructorWithStyle() {
+ TabWidget tabWidget = new TabWidget(mActivity, null, 0, R.style.TabWidgetCustomStyle);
+
+ assertFalse(tabWidget.isStripEnabled());
+
+ Drawable leftStripDrawable = tabWidget.getLeftStripDrawable();
+ assertNotNull(leftStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Left strip green", leftStripDrawable,
+ leftStripDrawable.getIntrinsicWidth(), leftStripDrawable.getIntrinsicHeight(),
+ true, 0xFF00FF00, 1, false);
+
+ Drawable rightStripDrawable = tabWidget.getRightStripDrawable();
+ assertNotNull(rightStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Right strip red", rightStripDrawable,
+ rightStripDrawable.getIntrinsicWidth(), rightStripDrawable.getIntrinsicHeight(),
+ true, 0xFFFF0000, 1, false);
+ }
+
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mActivity);
+ TabWidget tabWidget = (TabWidget) inflater.inflate(R.layout.tabhost_custom, null, false);
+
+ assertFalse(tabWidget.isStripEnabled());
+
+ Drawable leftStripDrawable = tabWidget.getLeftStripDrawable();
+ assertNotNull(leftStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Left strip red", leftStripDrawable,
+ leftStripDrawable.getIntrinsicWidth(), leftStripDrawable.getIntrinsicHeight(),
+ true, 0xFFFF0000, 1, false);
+
+ Drawable rightStripDrawable = tabWidget.getRightStripDrawable();
+ assertNotNull(rightStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Right strip green", rightStripDrawable,
+ rightStripDrawable.getIntrinsicWidth(), rightStripDrawable.getIntrinsicHeight(),
+ true, 0xFF00FF00, 1, false);
+ }
+
+ @UiThreadTest
+ public void testTabCount() {
+ TabHostCtsActivity activity = getActivity();
+ TabWidget tabWidget = activity.getTabWidget();
+
+ // We have one tab added in onCreate() of our activity
+ assertEquals(1, tabWidget.getTabCount());
+
+ for (int i = 1; i < 10; i++) {
+ tabWidget.addView(new TextView(mActivity));
+ assertEquals(i + 1, tabWidget.getTabCount());
+ }
+ }
+
+ @UiThreadTest
+ public void testTabViews() {
+ TabHostCtsActivity activity = getActivity();
+ TabWidget tabWidget = activity.getTabWidget();
+
+ // We have one tab added in onCreate() of our activity. We "reach" into the default tab
+ // indicator layout in the same way we do in TabHost_TabSpecTest tests.
+ TextView tab0 = (TextView) tabWidget.getChildTabViewAt(0).findViewById(android.R.id.title);
+ assertNotNull(tab0);
+ assertEquals(TabHostCtsActivity.INITIAL_TAB_LABEL, tab0.getText());
+
+ for (int i = 1; i < 10; i++) {
+ TextView toAdd = new TextView(mActivity);
+ toAdd.setText("Tab #" + i);
+ tabWidget.addView(toAdd);
+ assertEquals(toAdd, tabWidget.getChildTabViewAt(i));
+ }
+ }
+
public void testChildDrawableStateChanged() {
MockTabWidget mockTabWidget = new MockTabWidget(mActivity);
TextView tv0 = new TextView(mActivity);
@@ -138,8 +213,11 @@
}
}
+ @UiThreadTest
public void testSetEnabled() {
- TabWidget tabWidget = new TabWidget(mActivity);
+ TabHostCtsActivity activity = getActivity();
+ TabWidget tabWidget = activity.getTabWidget();
+
tabWidget.addView(new TextView(mActivity));
tabWidget.addView(new TextView(mActivity));
assertTrue(tabWidget.isEnabled());
@@ -194,6 +272,78 @@
}
}
+ @UiThreadTest
+ public void testStripEnabled() {
+ TabHostCtsActivity activity = getActivity();
+ TabWidget tabWidget = activity.getTabWidget();
+
+ tabWidget.setStripEnabled(true);
+ assertTrue(tabWidget.isStripEnabled());
+
+ tabWidget.setStripEnabled(false);
+ assertFalse(tabWidget.isStripEnabled());
+ }
+
+ @UiThreadTest
+ public void testStripDrawables() {
+ TabHostCtsActivity activity = getActivity();
+ TabWidget tabWidget = activity.getTabWidget();
+
+ // Test setting left strip drawable
+ tabWidget.setLeftStripDrawable(R.drawable.icon_green);
+ Drawable leftStripDrawable = tabWidget.getLeftStripDrawable();
+ assertNotNull(leftStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Left strip green", leftStripDrawable,
+ leftStripDrawable.getIntrinsicWidth(), leftStripDrawable.getIntrinsicHeight(),
+ true, 0xFF00FF00, 1, false);
+
+ tabWidget.setLeftStripDrawable(activity.getResources().getDrawable(
+ R.drawable.icon_red, null));
+ leftStripDrawable = tabWidget.getLeftStripDrawable();
+ assertNotNull(leftStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Left strip red", leftStripDrawable,
+ leftStripDrawable.getIntrinsicWidth(), leftStripDrawable.getIntrinsicHeight(),
+ true, 0xFFFF0000, 1, false);
+
+ // Test setting right strip drawable
+ tabWidget.setRightStripDrawable(R.drawable.icon_red);
+ Drawable rightStripDrawable = tabWidget.getRightStripDrawable();
+ assertNotNull(rightStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Right strip red", rightStripDrawable,
+ rightStripDrawable.getIntrinsicWidth(), rightStripDrawable.getIntrinsicHeight(),
+ true, 0xFFFF0000, 1, false);
+
+ tabWidget.setRightStripDrawable(activity.getResources().getDrawable(
+ R.drawable.icon_green, null));
+ rightStripDrawable = tabWidget.getRightStripDrawable();
+ assertNotNull(rightStripDrawable);
+ TestUtils.assertAllPixelsOfColor("Left strip green", rightStripDrawable,
+ rightStripDrawable.getIntrinsicWidth(), rightStripDrawable.getIntrinsicHeight(),
+ true, 0xFF00FF00, 1, false);
+ }
+
+ @UiThreadTest
+ public void testDividerDrawables() {
+ TabHostCtsActivity activity = getActivity();
+ TabWidget tabWidget = activity.getTabWidget();
+
+ tabWidget.setDividerDrawable(R.drawable.icon_blue);
+ Drawable dividerDrawable = tabWidget.getDividerDrawable();
+ assertNotNull(dividerDrawable);
+ TestUtils.assertAllPixelsOfColor("Divider blue", dividerDrawable,
+ dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
+ true, 0xFF0000FF, 1, false);
+
+ tabWidget.setDividerDrawable(activity.getResources().getDrawable(
+ R.drawable.icon_yellow, null));
+ dividerDrawable = tabWidget.getDividerDrawable();
+ assertNotNull(dividerDrawable);
+ TestUtils.assertAllPixelsOfColor("Divider yellow", dividerDrawable,
+ dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
+ true, 0xFFFFFF00, 1, false);
+
+ }
+
public void testOnFocusChange() {
// onFocusChange() is implementation details, do NOT test
}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 406e079..a95e43d 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -16,14 +16,6 @@
package android.widget.cts;
-import android.graphics.drawable.ColorDrawable;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.Html;
-import android.text.Spanned;
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
@@ -42,6 +34,7 @@
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -49,13 +42,16 @@
import android.test.ActivityInstrumentationTestCase2;
import android.test.TouchUtils;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.text.Editable;
+import android.text.Html;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
+import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
@@ -76,13 +72,14 @@
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
import android.text.style.URLSpan;
+import android.text.style.UnderlineSpan;
import android.text.util.Linkify;
import android.util.DisplayMetrics;
import android.util.LocaleList;
import android.util.TypedValue;
+import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.ActionMode;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
@@ -105,6 +102,8 @@
import android.widget.TextView.BufferType;
import android.widget.TextView.OnEditorActionListener;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.util.Locale;
@@ -824,6 +823,39 @@
assertEquals(0, mTextView.getLineHeight());
}
+ public void testSetElegantLineHeight() {
+ mTextView = findTextView(R.id.textview_text);
+ assertFalse(mTextView.getPaint().isElegantTextHeight());
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setWidth(mTextView.getWidth() / 3);
+ mTextView.setPadding(1, 2, 3, 4);
+ mTextView.setGravity(Gravity.BOTTOM);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ int oldHeight = mTextView.getHeight();
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setElegantTextHeight(true);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mTextView.getPaint().isElegantTextHeight());
+ assertTrue(mTextView.getHeight() > oldHeight);
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setElegantTextHeight(false);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertFalse(mTextView.getPaint().isElegantTextHeight());
+ assertTrue(mTextView.getHeight() == oldHeight);
+ }
+
public void testInstanceState() {
// Do not test. Implementation details.
}
@@ -2391,6 +2423,7 @@
public void testSetIncludeFontPadding() {
mTextView = findTextView(R.id.textview_text);
+ assertTrue(mTextView.getIncludeFontPadding());
mActivity.runOnUiThread(new Runnable() {
public void run() {
mTextView.setWidth(mTextView.getWidth() / 3);
@@ -2409,6 +2442,7 @@
mInstrumentation.waitForIdleSync();
assertTrue(mTextView.getHeight() < oldHeight);
+ assertFalse(mTextView.getIncludeFontPadding());
}
public void testScroll() {
@@ -3981,10 +4015,53 @@
mTextView.getText().toString());
ExtractedText et = new ExtractedText();
+
+ // Update text and selection.
et.text = "test";
+ et.selectionStart = 0;
+ et.selectionEnd = 2;
mTextView.setExtractedText(et);
assertEquals("test", mTextView.getText().toString());
+ assertEquals(0, mTextView.getSelectionStart());
+ assertEquals(2, mTextView.getSelectionEnd());
+
+ // Use partialStartOffset and partialEndOffset
+ et.partialStartOffset = 2;
+ et.partialEndOffset = 3;
+ et.text = "x";
+ et.selectionStart = 2;
+ et.selectionEnd = 3;
+
+ mTextView.setExtractedText(et);
+ assertEquals("text", mTextView.getText().toString());
+ assertEquals(2, mTextView.getSelectionStart());
+ assertEquals(3, mTextView.getSelectionEnd());
+
+ // Update text with spans.
+ final SpannableString ss = new SpannableString("ex");
+ ss.setSpan(new UnderlineSpan(), 0, 2, 0);
+ ss.setSpan(new URLSpan("ctstest://TextView/test"), 1, 2, 0);
+
+ et.text = ss;
+ et.partialStartOffset = 1;
+ et.partialEndOffset = 3;
+ mTextView.setExtractedText(et);
+
+ assertEquals("text", mTextView.getText().toString());
+ final Editable editable = mTextView.getEditableText();
+ final UnderlineSpan[] underlineSpans = mTextView.getEditableText().getSpans(
+ 0, editable.length(), UnderlineSpan.class);
+ assertEquals(1, underlineSpans.length);
+ assertEquals(1, editable.getSpanStart(underlineSpans[0]));
+ assertEquals(3, editable.getSpanEnd(underlineSpans[0]));
+
+ final URLSpan[] urlSpans = mTextView.getEditableText().getSpans(
+ 0, editable.length(), URLSpan.class);
+ assertEquals(1, urlSpans.length);
+ assertEquals(2, editable.getSpanStart(urlSpans[0]));
+ assertEquals(3, editable.getSpanEnd(urlSpans[0]));
+ assertEquals("ctstest://TextView/test", urlSpans[0].getURL());
}
public void testMoveCursorToVisibleOffset() throws Throwable {
diff --git a/tests/tests/widget/src/android/widget/cts/util/TestUtils.java b/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
new file mode 100644
index 0000000..3b11d0e
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/util/TestUtils.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.widget.cts.util;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewParent;
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestUtils {
+ /**
+ * This method takes a view and returns a single bitmap that is the layered combination
+ * of background drawables of this view and all its ancestors. It can be used to abstract
+ * away the specific implementation of a view hierarchy that is not exposed via class APIs
+ * or a view hierarchy that depends on the platform version. Instead of hard-coded lookups
+ * of particular inner implementations of such a view hierarchy that can break during
+ * refactoring or on newer platform versions, calling this API returns a "combined" background
+ * of the view.
+ *
+ * For example, it is useful to get the combined background of a popup / dropdown without
+ * delving into the inner implementation details of how that popup is implemented on a
+ * particular platform version.
+ */
+ public static Bitmap getCombinedBackgroundBitmap(View view) {
+ final int bitmapWidth = view.getWidth();
+ final int bitmapHeight = view.getHeight();
+
+ // Create a bitmap
+ final Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight,
+ Bitmap.Config.ARGB_8888);
+ // Create a canvas that wraps the bitmap
+ final Canvas canvas = new Canvas(bitmap);
+
+ // As the draw pass starts at the top of view hierarchy, our first step is to traverse
+ // the ancestor hierarchy of our view and collect a list of all ancestors with non-null
+ // and visible backgrounds. At each step we're keeping track of the combined offsets
+ // so that we can properly combine all of the visuals together in the next pass.
+ List<View> ancestorsWithBackgrounds = new ArrayList<>();
+ List<Pair<Integer, Integer>> ancestorOffsets = new ArrayList<>();
+ int offsetX = 0;
+ int offsetY = 0;
+ while (true) {
+ final Drawable backgroundDrawable = view.getBackground();
+ if ((backgroundDrawable != null) && backgroundDrawable.isVisible()) {
+ ancestorsWithBackgrounds.add(view);
+ ancestorOffsets.add(Pair.create(offsetX, offsetY));
+ }
+ // Go to the parent
+ ViewParent parent = view.getParent();
+ if (!(parent instanceof View)) {
+ // We're done traversing the ancestor chain
+ break;
+ }
+
+ // Update the offsets based on the location of current view in its parent's bounds
+ offsetX += view.getLeft();
+ offsetY += view.getTop();
+
+ view = (View) parent;
+ }
+
+ // Now we're going to iterate over the collected ancestors in reverse order (starting from
+ // the topmost ancestor) and draw their backgrounds into our combined bitmap. At each step
+ // we are respecting the offsets of our original view in the coordinate system of the
+ // currently drawn ancestor.
+ final int layerCount = ancestorsWithBackgrounds.size();
+ for (int i = layerCount - 1; i >= 0; i--) {
+ View ancestor = ancestorsWithBackgrounds.get(i);
+ Pair<Integer, Integer> offsets = ancestorOffsets.get(i);
+
+ canvas.translate(offsets.first, offsets.second);
+ ancestor.getBackground().draw(canvas);
+ canvas.translate(-offsets.first, -offsets.second);
+ }
+
+ return bitmap;
+ }
+
+ /**
+ * Checks whether all the pixels in the specified drawable are of the same specified color.
+ *
+ * In case there is a color mismatch, the behavior of this method depends on the
+ * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+ * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+ * <code>Assert.fail</code> with detailed description of the mismatch.
+ */
+ public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
+ int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
+ int allowedComponentVariance, boolean throwExceptionIfFails) {
+ // Create a bitmap
+ Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight,
+ Bitmap.Config.ARGB_8888);
+ // Create a canvas that wraps the bitmap
+ Canvas canvas = new Canvas(bitmap);
+ if (callSetBounds) {
+ // Configure the drawable to have bounds that match the passed size
+ drawable.setBounds(0, 0, drawableWidth, drawableHeight);
+ }
+ // And ask the drawable to draw itself to the canvas / bitmap
+ drawable.draw(canvas);
+
+ try {
+ assertAllPixelsOfColor(failMessagePrefix, bitmap, drawableWidth, drawableHeight, color,
+ allowedComponentVariance, throwExceptionIfFails);
+ } finally {
+ bitmap.recycle();
+ }
+ }
+
+ /**
+ * Checks whether all the pixels in the specified bitmap are of the same specified color.
+ *
+ * In case there is a color mismatch, the behavior of this method depends on the
+ * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+ * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+ * <code>Assert.fail</code> with detailed description of the mismatch.
+ */
+ public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
+ int bitmapWidth, int bitmapHeight, @ColorInt int color,
+ int allowedComponentVariance, boolean throwExceptionIfFails) {
+ int[] rowPixels = new int[bitmapWidth];
+ for (int row = 0; row < bitmapHeight; row++) {
+ bitmap.getPixels(rowPixels, 0, bitmapWidth, 0, row, bitmapWidth, 1);
+ for (int column = 0; column < bitmapWidth; column++) {
+ int sourceAlpha = Color.alpha(rowPixels[column]);
+ int sourceRed = Color.red(rowPixels[column]);
+ int sourceGreen = Color.green(rowPixels[column]);
+ int sourceBlue = Color.blue(rowPixels[column]);
+
+ int expectedAlpha = Color.alpha(color);
+ int expectedRed = Color.red(color);
+ int expectedGreen = Color.green(color);
+ int expectedBlue = Color.blue(color);
+
+ int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
+ int varianceRed = Math.abs(sourceRed - expectedRed);
+ int varianceGreen = Math.abs(sourceGreen - expectedGreen);
+ int varianceBlue = Math.abs(sourceBlue - expectedBlue);
+
+ boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
+ && (varianceRed <= allowedComponentVariance)
+ && (varianceGreen <= allowedComponentVariance)
+ && (varianceBlue <= allowedComponentVariance);
+
+ if (!isColorMatch) {
+ String mismatchDescription = failMessagePrefix
+ + ": expected all drawable colors to be ["
+ + expectedAlpha + "," + expectedRed + ","
+ + expectedGreen + "," + expectedBlue
+ + "] but at position (" + row + "," + column + ") out of ("
+ + bitmapWidth + "," + bitmapHeight + ") found ["
+ + sourceAlpha + "," + sourceRed + ","
+ + sourceGreen + "," + sourceBlue + "]";
+ if (throwExceptionIfFails) {
+ throw new RuntimeException(mismatchDescription);
+ } else {
+ Assert.fail(mismatchDescription);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
index ca6c528..02ac28c 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
@@ -23,7 +23,7 @@
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnDrawListener;
-import java.util.concurrent.Semaphore;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
@@ -41,34 +41,25 @@
*/
public static void runOnMainAndDrawSync(Instrumentation instrumentation,
final View view, final Runnable runner) {
- final Semaphore token = new Semaphore(0);
- final Runnable releaseToken = new Runnable() {
- @Override
- public void run() {
- token.release();
- }
- };
+ final CountDownLatch latch = new CountDownLatch(1);
- instrumentation.runOnMainSync(new Runnable() {
- @Override
- public void run() {
- final ViewTreeObserver observer = view.getViewTreeObserver();
- final OnDrawListener listener = new OnDrawListener() {
- @Override
- public void onDraw() {
- observer.removeOnDrawListener(this);
- view.post(releaseToken);
- }
- };
+ instrumentation.runOnMainSync(() -> {
+ final ViewTreeObserver observer = view.getViewTreeObserver();
+ final OnDrawListener listener = new OnDrawListener() {
+ @Override
+ public void onDraw() {
+ observer.removeOnDrawListener(this);
+ view.post(() -> latch.countDown());
+ }
+ };
- observer.addOnDrawListener(listener);
- runner.run();
- }
+ observer.addOnDrawListener(listener);
+ runner.run();
});
try {
Assert.assertTrue("Expected draw pass occurred within 5 seconds",
- token.tryAcquire(5, TimeUnit.SECONDS));
+ latch.await(5, TimeUnit.SECONDS));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
diff --git a/tests/vm/AndroidTest.xml b/tests/vm/AndroidTest.xml
index 2bac07b..fc1098b 100644
--- a/tests/vm/AndroidTest.xml
+++ b/tests/vm/AndroidTest.xml
@@ -20,5 +20,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.vm.cts" />
+ <option name="runtime-hint" value="20m14s" />
</test>
</configuration>
diff --git a/tools/cts-tradefed/res/config/collect-tests-only.xml b/tools/cts-tradefed/res/config/collect-tests-only.xml
new file mode 100644
index 0000000..1c22b11
--- /dev/null
+++ b/tools/cts-tradefed/res/config/collect-tests-only.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.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+ <include name="cts" />
+
+ <!-- This tells cts-tradefed and the server what the plan name is, reports that have this plan
+ name should not be accepted, as it doesn't actually run the tests it simply marks all of
+ them as passed.
+ Obviously no one would modify the report before uploadng to falsify this
+ information, as that would be dishonest, and dishonesty kills kittens :'( -->
+ <option name="compatibility:plan" value="collect-tests-only" />
+
+ <!-- Tell all AndroidJUnitTests to only list the tests -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:collect-tests-only:true" />
+
+ <!-- Tell all GTests to only list the tests -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.GTest:collect-tests-only:true" />
+
+ <!-- Tell all HostTests to only list the tests -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:collect-tests-only:true" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
new file mode 100644
index 0000000..4d656b1
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -0,0 +1,218 @@
+<?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 with CTS known failures" >
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME" /> Excludes whole module -->
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME PACKAGE_NAME" /> Excludes whole package -->
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME PACKAGE_NAME.CLASS_NAME" /> Excludes whole class -->
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME PACKAGE_NAME.CLASS_NAME#TEST_NAME" /> Excludes individual test -->
+
+ <!-- b/17595050 -->
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverTextExtend" />
+
+ <!-- b/17508787 -->
+ <option name="compatibility:exclude-filter" value="CtsAdminTestCases android.admin.cts.DevicePolicyManagerTest#testUninstallAllUserCaCerts_failIfNotProfileOwner" />
+
+ <!-- b/23776083 -->
+ <option name="compatibility:exclude-filter" value="CtsAlarmClockTestCases android.alarmclock.cts.DismissAlarmTest#testAll" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmClockTestCases android.alarmclock.cts.SetAlarmTest#testAll" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmClockTestCases android.alarmclock.cts.SnoozeAlarmTest#testAll" />
+
+ <!-- b/17993121 -->
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testBindAppWidget" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testCollectionWidgets" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testDeleteHost" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testDeleteHosts" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testGetAppWidgetIds" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testGetAppWidgetInfo" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testGetAppWidgetOptions" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetId" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetIds" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testTwoAppWidgetProviderCallbacks" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaComponentName" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId" />
+ <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds" />
+
+ <!-- b/21668302 -->
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.AssistantContentViewTest#testAssistantContentViewDimens" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ExtraAssistDataTest#testAssistContentAndAssistData" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.FocusChangeTest#testLayerCausesUnderlyingActivityToLoseFocus" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.LargeViewHierarchyTest#testTextView" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ScreenshotTest#testBlueScreenshot" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ScreenshotTest#testGreenScreenshot" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ScreenshotTest#testRedScreenshot" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.TextViewTest#testTextView" />
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.WebViewTest#testWebView" />
+
+ <!-- b/23776099 -->
+ <option name="compatibility:exclude-filter" value="CtsCallLogTestCases android.calllog.cts.CallLogBackupTest#testSingleCallBackup" />
+
+ <!-- b/17530117 -->
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.AllocationTest#testBlackWhite" />
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.AllocationTest#testParamSensitivity" />
+ <!-- b/17989532 -->
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.SurfaceViewPreviewTest#testPreparePerformance" />
+ <!-- b/23008511 -->
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.cts.CameraTest#testPreviewFpsRange" />
+
+ <option name="compatibility:exclude-filter" value="CtsCarTestCases" />
+
+ <!-- b/27578806 -->
+ <option name="compatibility:exclude-filter" value="CtsCppToolsTestCases com.android.cts.cpptools.RunAsHostTest#testRunAs" />
+
+ <!-- b/23776893 -->
+ <option name="compatibility:exclude-filter" value="CtsDumpsysHostTestCases android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput" />
+ <option name="compatibility:exclude-filter" value="CtsDumpsysHostTestCases android.dumpsys.cts.DumpsysHostTest#testGfxinfoFramestats" />
+
+ <!-- b/22922206 b/27534791 -->
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testAccelerometer_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGravity_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGravity_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_50hz_flush" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testLinearAcceleration_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testLinearAcceleration_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticField_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticField_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticFieldUncalibrated_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticFieldUncalibrated_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testPressure_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testPressure_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_flush" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_fastest_batching" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorIntegrationTests#testSensorsMovingRates" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorIntegrationTests#testSensorsWithSeveralClients" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorTest#testBatchAndFlush" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorTest#testSensorTimeStamps" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testGyroscope_15hz" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testGyroscope_1hz" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testMagneticField_1hz" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testMagneticField_50hz" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testMagneticFieldUncalibrated_200hz" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testOrientation_5hz" />
+
+ <!-- b/16720689 -->
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch002" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch003" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch004" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger001#testDebugger002" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger002#testDebugger" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTest#testClassUnloadEvent" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnteredTest#testMonitorContendedEnteredForClassMatch" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnterTest#testMonitorContendedEnterForClassMatch" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassExclude" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchExact" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchFirst" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchSecond" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassOnly" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassExclude" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchExact" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchFirst" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchSecond" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassOnly" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ReferenceType.ClassFileVersionTest#testClassFileVersion001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ReferenceType.NestedTypesTest#testNestedTypes001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ThreadReference.StopTest#testStop001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.VirtualMachine.HoldEventsTest#testHoldEvents001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ReleaseEventsTest#testReleaseEvents001" />
+
+ <!-- b/18117279 b/21262226 b/23144425 -->
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withMobile" />
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withWifi" />
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintExecutes_withWifi" />
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintFails_withMobile" />
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.TimingConstraintsTest#testJobParameters_unexpiredDeadline" />
+
+ <!-- b/25850508 -->
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testCopyMediaFiles" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testGetMaxVideoPlaybackResolutionFound" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testGetMaxVideoPlaybackResolutionNotFound" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testMediaFilesExistOnDeviceFalse" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testMediaFilesExistOnDeviceTrue" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testSetMountPoint" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testSkipMediaDownload" />
+
+ <!-- b/17144778 -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ImageReaderDecoderTest#testHwAVCDecode360pForFlexibleYuv" />
+ <!-- b/23827982 -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH264FlexArbitraryW" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH264SurfArbitraryW" />
+
+ <!-- b/25651805 -->
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.ConnectivityManagerTest#testRestrictedNetworks" />
+ <!-- b/18682315 -->
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#testCreateSocket" />
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_bind" />
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_simple" />
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_wrapping" />
+
+ <!-- b/17394321 -->
+ <option name="compatibility:exclude-filter" value="CtsOpenGlPerfTestCases android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingFast" />
+ <option name="compatibility:exclude-filter" value="CtsOpenGlPerfTestCases android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingSlow" />
+
+ <!-- b/18091590 -->
+ <option name="compatibility:exclude-filter" value="CtsOpenGlPerfTestCases android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers" />
+
+ <!-- b/23192492 -->
+ <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts" />
+
+ <option name="compatibility:exclude-filter" value="CtsSampleDeviceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSampleHostTestCases" />
+
+ <!-- b/18461670 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_getStreamVolumeLeak" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_isStreamActive" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_isStreamActiveRemotely" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_startAudioSource" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_startOutput" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_stopOutput" />
+ <!-- b/27218502 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.MediaCryptoTest#testMediaCryptoClearKey" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.MediaCryptoTest#testMediaCryptoWidevine" />
+
+ <!-- b/26150806 -->
+ <option name="compatibility:exclude-filter" value="CtsSignatureTestCases android.signature.cts.tests" />
+
+ <!-- b/23427621 -->
+ <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.LightStatusBarTests#testLightStatusBarIcons" />
+
+ <!-- b/23604254 -->
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.ExtendedInCallServiceTest#testAddNewOutgoingCallAndThenDisconnect" />
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.RemoteConferenceTest#testRemoteConferenceCallbacks_ConferenceableConnections" />
+
+ <!-- b/23979591 -->
+ <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.CellInfoTest#testCellInfo" />
+
+ <!-- b/23779020 -->
+ <option name="compatibility:exclude-filter" value="CtsTransitionTestCases android.transition.cts.ChangeScrollTest#testChangeScroll" />
+
+ <!-- b/17536113 -->
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testNoAccessSilentlyFails" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testOrderedActivityLaunchSequenceInEventLog" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testPackageUsageStatsIntervals" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testUsageEventsParceling" />
+
+ <!-- b/23238984 -->
+ <option name="compatibility:exclude-filter" value="CtsVoiceSettingsTestCases android.voicesettings.cts.ZenModeTest#testAll" />
+
+ <!-- b/26235244 -->
+ <option name="compatibility:exclude-filter" value="android.util.cts.EventLogTest#testWriteEventWithOversizeValue" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-preconditions.xml b/tools/cts-tradefed/res/config/cts-preconditions.xml
index e01df10..efe8e3f 100644
--- a/tools/cts-tradefed/res/config/cts-preconditions.xml
+++ b/tools/cts-tradefed/res/config/cts-preconditions.xml
@@ -38,6 +38,7 @@
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="rm -rf /sdcard/device-info-files" />
+ <option name="run-command" value="rm -rf /sdcard/report-log-files" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInfoCollector">
@@ -47,4 +48,9 @@
<option name="dest-dir" value="device-info-files/"/>
</target_preparer>
+ <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/"/>
+ </target_preparer>
+
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
index 8104570..2eb0c3e 100644
--- a/tools/cts-tradefed/res/config/cts.xml
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -17,18 +17,12 @@
<include name="everything" />
<include name="cts-preconditions" />
+ <include name="cts-known-failures" />
<option name="compatibility:plan" value="cts" />
<option name="enable-root" value="false" />
- <!-- Exclude sample test cases -->
- <option name="compatibility:exclude-filter" value="CtsSampleDeviceTestCases" />
- <option name="compatibility:exclude-filter" value="CtsSampleHostTestCases" />
-
- <!-- Exclude automotive only test cases for now -->
- <option name="compatibility:exclude-filter" value="CtsAutomotiveTestCases" />
-
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
<option name="property-name" value="ro.build.type" />
<option name="expected-value" value="user"/> <!-- Device should have user build -->
@@ -41,4 +35,5 @@
<option name="throw-error" value="false"/> <!-- Only print warning if not en-US -->
</target_preparer>
<template-include name="reporters" default="basic-reporters" />
+
</configuration>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index b75a67a..b68073d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -316,10 +316,6 @@
// mName means 'apk file name' for instrumentation tests
instrTest.addInstallApk(String.format("%s.apk", mName), mAppNameSpace);
mDigest = generateDigest(testCaseDir, String.format("%s.apk", mName));
- if (mTests.size() > 1000) {
- // TODO: hack, large test suites can take longer to collect tests, increase timeout
- instrTest.setCollectsTestsShellTimeout(10 * 60 * 1000);
- }
return instrTest;
}
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 9923fcd..f983b15 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -118,20 +118,20 @@
packages.sort()
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
+ plan.Exclude('android\.car')
plan.Exclude('android\.performance.*')
self.__WritePlan(plan, 'CTS')
self.__WritePlan(plan, 'CTS-TF')
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
+ plan.Exclude('android\.car')
plan.Exclude('android\.performance.*')
plan.Exclude('android\.media\.cts\.StreamingMediaPlayerTest.*')
# Test plan to not include media streaming tests
self.__WritePlan(plan, 'CTS-No-Media-Stream')
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
+ plan.Exclude('android\.car')
plan.Exclude('android\.performance.*')
self.__WritePlan(plan, 'SDK')
@@ -140,19 +140,16 @@
self.__WritePlan(plan, 'Android')
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
plan.Include(r'android\.core\.tests.*')
plan.Exclude(r'android\.core\.tests\.libcore\.package\.harmony*')
self.__WritePlan(plan, 'Java')
# TODO: remove this once the tests are fixed and merged into Java plan above.
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
plan.Include(r'android\.core\.tests\.libcore\.package\.harmony*')
self.__WritePlan(plan, 'Harmony')
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
plan.Include(r'android\.core\.vm-tests-tf')
self.__WritePlan(plan, 'VM-TF')
@@ -174,7 +171,7 @@
plan.Include('android\.telephony')
plan.Include('android\.nativemedia.*')
plan.Include('com\.android\.cts\..*')#TODO(stuartscott): Should PDK have all these?
- plan.Exclude('android\.car.*')
+ plan.Exclude('android\.car')
self.__WritePlan(plan, 'PDK')
temporarily_known_failure_tests = BuildCtsTemporarilyKnownFailureList();
@@ -183,7 +180,7 @@
# CTS Stable plan
plan = tools.TestPlan(packages)
- plan.Exclude('android\.car.*')
+ plan.Exclude('android\.car')
plan.Exclude(r'android\.browser')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
@@ -198,7 +195,6 @@
for package, test_list in flaky_tests.iteritems():
plan.Include(package+'$')
plan.IncludeTests(package, test_list)
- plan.Exclude('android\.car.*')
self.__WritePlan(plan, 'CTS-flaky')
small_tests = BuildAospSmallSizeTestList()
@@ -211,7 +207,6 @@
for package, test_list in small_tests.iteritems():
plan.Include(package+'$')
plan.Exclude(r'android\.browser')
- plan.Exclude('android\.car.*')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
for package, test_list in releasekey_tests.iteritems():
@@ -229,7 +224,6 @@
plan.ExcludeTests(package, test_list)
for package, test_list in releasekey_tests.iteritems():
plan.ExcludeTests(package, test_list)
- plan.Exclude('android\.car.*')
self.__WritePlan(plan, 'CTS-kitkat-medium')
self.__WritePlan(plan, 'CTS-public-medium')
@@ -326,7 +320,7 @@
plan.Exclude(r'android\.view$')
plan.Exclude(r'android\.mediastress$')
plan.Exclude(r'android\.browser')
- plan.Exclude('android\.car.*')
+ plan.Exclude('android\.car')
for package, test_list in flaky_tests.iteritems():
plan.ExcludeTests(package, test_list)
for package, test_list in releasekey_tests.iteritems():
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 1704d84..ef6aa84 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -44,8 +44,7 @@
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit
-LOCAL_JAVA_LIBRARIES += jack
+LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit jsr305lib
LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)