Merge "update cts with renamed API getSlotIndex()" into oc-dev
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 9e98b79..070bada 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -63,7 +63,8 @@
# Not yet mandated tests
NOT_YET_MANDATED = {
"scene0": [
- "test_jitter"
+ "test_jitter",
+ "test_burst_capture"
],
"scene1": [
"test_ae_af",
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 99a4ee3..341575b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -992,6 +992,7 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="nosensor" />
+ <!-- FeatureSummaryActivity is replaced by CTS SystemFeaturesTest
<activity android:name=".features.FeatureSummaryActivity" android:label="@string/feature_summary">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -999,6 +1000,7 @@
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_features" />
</activity>
+ -->
<activity android:name=".location.GpsTestActivity"
android:label="@string/location_gps_test"
@@ -2394,6 +2396,10 @@
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_STATUS" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
+ <intent-filter>
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.BYOD_DISK_ENCRYPTION_STATUS" />
+ <category android:name="android.intent.category.DEFAULT"></category>
+ </intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
<meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
</activity>
@@ -2420,6 +2426,7 @@
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_QUERY" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_REMOVE" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.BYOD_CHECK_DISK_ENCRYPTION" />
<action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_IMAGE" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 02cb70f..1d3ea85 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2045,7 +2045,33 @@
The only way to disable the encryption is to factory reset the device.
</string>
<string name="provisioning_byod_profileowner">Profile owner installed</string>
- <string name="provisioning_byod_diskencryption">Full disk encryption enabled</string>
+ <string name="provisioning_byod_disk_encryption">Full disk encryption enabled</string>
+ <string name="provisioning_byod_disk_encryption_default_key_toast">
+ Cannot secure device with screen lock. Please re-run the test if you forgot to select
+ the \"require PIN to boot\" option.
+ </string>
+ <string name="provisioning_byod_disk_encryption_no_pin_toast">
+ No PIN is detected. Please re-run the test if you forgot to set a PIN.
+ </string>
+ <string name="provisioning_byod_set_screen_lock_dialog_message">
+ Next, you will be asked to set a screen lock for the device.\n
+ \n
+ Please set \"1111\" as the new PIN (or any other PIN that you can memorize).
+ You have to enter this PIN again later in order to finish the test.\n
+ \n
+ You may be asked whether the PIN should be required to boot the device. Please answer yes.\n
+ \n
+ Tap Go button to set a new screen lock.
+ </string>
+ <string name="provisioning_byod_remove_screen_lock_dialog_message">
+ The test is almost finished. \n
+ \n
+ Next, you will be asked to remove the screen lock that you just set. Please enter \"1111\"
+ (or your own PIN) when prompted for the old PIN, and do not set any new screen lock. This
+ is to make sure that the device returns to the initial state after this test.\n
+ \n
+ Tap Go button to remove existing screen lock.
+ </string>
<string name="provisioning_byod_profile_visible">Profile-aware accounts settings</string>
<string name="provisioning_byod_admin_visible">Profile-aware device administrator settings</string>
<string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index ffe29d2..8c779c5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -118,11 +118,16 @@
ICaseResult caseResult = moduleResult.getOrCreateResult(TEST_CASE_NAME);
int count = mAdapter.getCount();
+ int notExecutedCount = 0;
for (int i = 0; i < count; i++) {
TestListItem item = mAdapter.getItem(i);
if (item.isTest()) {
ITestResult currentTestResult = caseResult.getOrCreateResult(item.testName);
- currentTestResult.setResultStatus(getTestResultStatus(mAdapter.getTestResult(i)));
+ TestStatus resultStatus = getTestResultStatus(mAdapter.getTestResult(i));
+ if (resultStatus == null) {
+ ++notExecutedCount;
+ }
+ currentTestResult.setResultStatus(resultStatus);
// TODO: report test details with Extended Device Info (EDI) or CTS metrics
// String details = mAdapter.getTestDetails(i);
@@ -133,6 +138,7 @@
}
}
moduleResult.setDone(true);
+ moduleResult.setNotExecuted(notExecutedCount);
return result;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
index 1d585ac..035dc3f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
@@ -56,6 +56,10 @@
"<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
"<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
"</PeripheralProfile>" +
+ "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" +
+ "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+ "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+ "</PeripheralProfile>" +
"</ProfileList>";
// XML Tags and Attributes
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index d1977d8..395eac0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -246,6 +246,22 @@
new Feature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, false),
new Feature(PackageManager.FEATURE_PICTURE_IN_PICTURE, false),
new Feature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, false),
+ // FEATURE_FILE_BASED_ENCRYPTION is hide
+ new Feature("android.software.file_based_encryption", false),
+ };
+
+ public static final Feature[] ALL_O_FEATURES = {
+ new Feature(PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE, false),
+ // FEATURE_TELEPHONY_CARRIERLOCK is SystemApi
+ new Feature("android.hardware.telephony.carrierlock", false),
+ new Feature(PackageManager.FEATURE_WIFI_AWARE, false),
+ new Feature(PackageManager.FEATURE_EMBEDDED, false),
+ new Feature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP, false),
+ new Feature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS, false),
+ new Feature(PackageManager.FEATURE_VR_HEADTRACKING, false),
+ // FEATURE_CTS is hide
+ new Feature("android.software.cts", false),
+ new Feature(PackageManager.FEATURE_WIFI_AWARE, false),
};
@Override
@@ -279,6 +295,9 @@
// add features from latest to last so that the latest requirements are put in the set first
int apiVersion = Build.VERSION.SDK_INT;
+ if (apiVersion >= Build.VERSION_CODES.O) {
+ Collections.addAll(features, ALL_O_FEATURES);
+ }
if (apiVersion >= Build.VERSION_CODES.N) {
Collections.addAll(features, ALL_NYC_FEATURES);
}
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 f52d7eb..3b5632b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.managedprovisioning;
+import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -23,6 +24,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -30,6 +32,7 @@
import android.view.View.OnClickListener;
import android.widget.Toast;
+import com.android.compatibility.common.util.PropertyUtil;
import com.android.cts.verifier.ArrayTestListAdapter;
import com.android.cts.verifier.DialogTestListActivity;
import com.android.cts.verifier.R;
@@ -39,9 +42,10 @@
import com.android.cts.verifier.location.LocationListenerActivity;
/**
- * CTS verifier test for BYOD managed provisioning flow.
- * This activity is responsible for starting the managed provisioning flow and verify the outcome of provisioning.
- * It performs the following verifications:
+ * CTS verifier test for BYOD managed provisioning flow
+ *
+ * This activity is responsible for starting the managed provisioning flow and verify the outcome of
+ * provisioning. It performs the following verifications:
* Full disk encryption is enabled.
* Profile owner is correctly installed.
* Profile owner shows up in the Settings app.
@@ -51,15 +55,20 @@
*/
public class ByodFlowTestActivity extends DialogTestListActivity {
- private final String TAG = "ByodFlowTestActivity";
+ private static final String TAG = "ByodFlowTestActivity";
private static ConnectivityManager mCm;
private static final int REQUEST_MANAGED_PROVISIONING = 0;
private static final int REQUEST_PROFILE_OWNER_STATUS = 1;
private static final int REQUEST_INTENT_FILTERS_STATUS = 2;
+ private static final int REQUEST_CHECK_DISK_ENCRYPTION = 3;
+ private static final int REQUEST_SET_LOCK_FOR_ENCRYPTION = 4;
private ComponentName mAdminReceiverComponent;
+ private KeyguardManager mKeyguardManager;
+ private ByodFlowTestHelper mByodFlowTestHelper;
private DialogTestListItem mProfileOwnerInstalled;
+ private DialogTestListItem mDiskEncryptionTest;
private DialogTestListItem mProfileAccountVisibleTest;
private DialogTestListItem mDeviceAdminVisibleTest;
private DialogTestListItem mWorkAppVisibleTest;
@@ -109,9 +118,12 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mByodFlowTestHelper = new ByodFlowTestHelper(this);
mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+ mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
- enableComponent(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+ mByodFlowTestHelper.setup();
+
mPrepareTestButton.setText(R.string.provisioning_byod_start);
mPrepareTestButton.setOnClickListener(new OnClickListener() {
@Override
@@ -149,17 +161,24 @@
switch (requestCode) {
case REQUEST_MANAGED_PROVISIONING:
return;
- case REQUEST_PROFILE_OWNER_STATUS: {
+ case REQUEST_PROFILE_OWNER_STATUS:
// Called after queryProfileOwner()
handleStatusUpdate(resultCode, data);
- } break;
- case REQUEST_INTENT_FILTERS_STATUS: {
+ break;
+ case REQUEST_CHECK_DISK_ENCRYPTION:
+ // Called after checkDiskEncryption()
+ handleDiskEncryptionStatus(resultCode, data);
+ break;
+ case REQUEST_SET_LOCK_FOR_ENCRYPTION:
+ // Called after handleDiskEncryptionStatus() to set screen lock if necessary
+ handleSetLockForEncryption();
+ break;
+ case REQUEST_INTENT_FILTERS_STATUS:
// Called after checkIntentFilters()
handleIntentFiltersStatus(resultCode);
- } break;
- default: {
+ break;
+ default:
super.handleActivityResult(requestCode, resultCode, data);
- }
}
}
@@ -174,8 +193,7 @@
public void finish() {
// Pass and fail buttons are known to call finish() when clicked, and this is when we want to
// clean up the provisioned profile.
- Utils.requestDeleteManagedProfile(this);
- enableComponent(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+ mByodFlowTestHelper.tearDown();
super.finish();
}
@@ -190,6 +208,15 @@
}
};
+ mDiskEncryptionTest = new DialogTestListItem(this,
+ R.string.provisioning_byod_disk_encryption,
+ "BYOD_DiskEncryptionTest") {
+ @Override
+ public void performTest(DialogTestListActivity activity) {
+ checkDiskEncryption();
+ }
+ };
+
/*
* To keep the image in this test up to date, use the instructions in
* {@link ByodIconSamplerActivity}.
@@ -399,6 +426,11 @@
policyTransparencyTestIntent, null);
adapter.add(mProfileOwnerInstalled);
+ if (PropertyUtil.getFirstApiLevel() >= VERSION_CODES.N_MR1) {
+ // Previous devices were not required to entangle the disk encryption key with lock
+ // screen credentials.
+ adapter.add(mDiskEncryptionTest);
+ }
// Badge related tests
adapter.add(mWorkAppVisibleTest);
@@ -605,6 +637,59 @@
}
}
+ private void checkDiskEncryption() {
+ try {
+ Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_DISK_ENCRYPTION);
+ startActivityForResult(intent, REQUEST_CHECK_DISK_ENCRYPTION);
+ } catch (ActivityNotFoundException e) {
+ Log.d(TAG, "checkDiskEncryption: ActivityNotFoundException", e);
+ setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+ Utils.showToast(this, R.string.provisioning_byod_no_activity);
+ }
+ }
+
+ private void handleDiskEncryptionStatus(int resultCode, Intent data) {
+ if (resultCode != RESULT_OK || data == null) {
+ Log.e(TAG, "Failed to get result for disk encryption, result code: " + resultCode);
+ setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+ return;
+ }
+
+ final int status = data.getIntExtra(ByodHelperActivity.EXTRA_ENCRYPTION_STATUS,
+ DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED);
+ switch (status) {
+ case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
+ case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
+ setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_PASSED);
+ break;
+ case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY:
+ if (!mKeyguardManager.isDeviceSecure()) {
+ Utils.setScreenLock(this, REQUEST_SET_LOCK_FOR_ENCRYPTION);
+ return;
+ }
+ Log.e(TAG, "Disk encryption key is not entangled with lock screen credentials");
+ Toast.makeText(this, R.string.provisioning_byod_disk_encryption_default_key_toast,
+ Toast.LENGTH_LONG).show();
+ // fall through
+ default:
+ setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+ }
+
+ if (mKeyguardManager.isDeviceSecure()) {
+ Utils.removeScreenLock(this);
+ }
+ }
+
+ private void handleSetLockForEncryption() {
+ if (mKeyguardManager.isDeviceSecure()) {
+ checkDiskEncryption();
+ } else {
+ setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+ Toast.makeText(this, R.string.provisioning_byod_disk_encryption_no_pin_toast,
+ Toast.LENGTH_LONG).show();
+ }
+ }
+
private void checkIntentFilters() {
try {
// Enable component HandleIntentActivity before intent filters are checked.
@@ -640,29 +725,6 @@
intentFiltersSet ? TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
}
- /**
- * Disable or enable app components in the current profile. When they are disabled only the
- * counterpart in the other profile can respond (via cross-profile intent filter).
- * @param enabledState {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED} or
- * {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
- */
- private void enableComponent(final int enabledState) {
- final String[] components = {
- ByodHelperActivity.class.getName(),
- WorkStatusTestActivity.class.getName(),
- PermissionLockdownTestActivity.ACTIVITY_ALIAS,
- AuthenticationBoundKeyTestActivity.class.getName(),
- VpnTestActivity.class.getName(),
- RecentsRedactionActivity.class.getName(),
- CommandReceiverActivity.class.getName(),
- SetSupportMessageActivity.class.getName()
- };
- for (String component : components) {
- getPackageManager().setComponentEnabledSetting(new ComponentName(this, component),
- enabledState, PackageManager.DONT_KILL_APP);
- }
- }
-
private void setHandleIntentActivityEnabledSetting(final int enableState) {
getPackageManager().setComponentEnabledSetting(
new ComponentName(ByodFlowTestActivity.this, HandleIntentActivity.class.getName()),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
new file mode 100644
index 0000000..d1308ad
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
@@ -0,0 +1,51 @@
+package com.android.cts.verifier.managedprovisioning;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+public class ByodFlowTestHelper {
+ private Context mContext;
+ private PackageManager mPackageManager;
+
+ public ByodFlowTestHelper(Context context) {
+ this.mContext = context;
+ this.mPackageManager = mContext.getPackageManager();
+ }
+
+ public void setup() {
+ setComponentsEnabledState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+ }
+
+ /**
+ * Clean up things. This has to be working even it is called multiple times.
+ */
+ public void tearDown() {
+ Utils.requestDeleteManagedProfile(mContext);
+ setComponentsEnabledState(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+ }
+
+ /**
+ * Disable or enable app components in the current profile. When they are disabled only the
+ * counterpart in the other profile can respond (via cross-profile intent filter).
+ *
+ * @param enabledState {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED} or
+ * {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
+ */
+ private void setComponentsEnabledState(final int enabledState) {
+ final String[] components = {
+ ByodHelperActivity.class.getName(),
+ WorkStatusTestActivity.class.getName(),
+ PermissionLockdownTestActivity.ACTIVITY_ALIAS,
+ AuthenticationBoundKeyTestActivity.class.getName(),
+ VpnTestActivity.class.getName(),
+ RecentsRedactionActivity.class.getName(),
+ CommandReceiverActivity.class.getName(),
+ SetSupportMessageActivity.class.getName()
+ };
+ for (String component : components) {
+ mPackageManager.setComponentEnabledSetting(new ComponentName(mContext, component),
+ enabledState, PackageManager.DONT_KILL_APP);
+ }
+ }
+}
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 6ad1634..e9b6523 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -81,6 +81,15 @@
public static final String EXTRA_PROVISIONED = "extra_provisioned";
public static final String EXTRA_PARAMETER_1 = "extra_parameter_1";
+ // Primary -> managed intent: check if the disk of the device is encrypted
+ public static final String ACTION_CHECK_DISK_ENCRYPTION =
+ "com.android.cts.verifier.managedprovisioning.action.BYOD_CHECK_DISK_ENCRYPTION";
+ // Managed -> primary intent: update disk encryption status in primary's CtsVerifier
+ public static final String ACTION_DISK_ENCRYPTION_STATUS =
+ "com.android.cts.verifier.managedprovisioning.action.BYOD_DISK_ENCRYPTION_STATUS";
+ // Int extra field indicating the encryption status of the device storage
+ public static final String EXTRA_ENCRYPTION_STATUS = "extra_encryption_status";
+
// Primary -> managed intent: set unknown sources restriction and install package
public static final String ACTION_INSTALL_APK = "com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK";
public static final String EXTRA_ALLOW_NON_MARKET_APPS = "allow_non_market_apps";
@@ -212,6 +221,11 @@
mDevicePolicyManager.wipeData(0);
showToast(R.string.provisioning_byod_profile_deleted);
}
+ } else if (action.equals(ACTION_CHECK_DISK_ENCRYPTION)) {
+ final int status = mDevicePolicyManager.getStorageEncryptionStatus();
+ final Intent response = new Intent(ACTION_DISK_ENCRYPTION_STATUS)
+ .putExtra(EXTRA_ENCRYPTION_STATUS, status);
+ setResult(RESULT_OK, response);
} else if (action.equals(ACTION_INSTALL_APK)) {
boolean allowNonMarket = intent.getBooleanExtra(EXTRA_ALLOW_NON_MARKET_APPS, false);
boolean wasAllowed = !isUnknownSourcesRestrictionSet();
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 a59abbc..1c40ac1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -85,6 +85,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
filter.addAction(ByodHelperActivity.ACTION_REMOVE_MANAGED_PROFILE);
+ filter.addAction(ByodHelperActivity.ACTION_CHECK_DISK_ENCRYPTION);
filter.addAction(ByodHelperActivity.ACTION_INSTALL_APK);
filter.addAction(ByodHelperActivity.ACTION_CHECK_INTENT_FILTERS);
filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_IMAGE);
@@ -122,6 +123,7 @@
// Work -> primary direction
filter = new IntentFilter();
filter.addAction(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+ filter.addAction(ByodHelperActivity.ACTION_DISK_ENCRYPTION_STATUS);
filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL);
filter.addAction(LocationListenerActivity.ACTION_SET_LOCATION_AND_CHECK_UPDATES);
dpm.addCrossProfileIntentFilter(getWho(context), filter,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 67e7fd4..0cae6be 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -78,6 +78,10 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ // Tidy up in case previous run crashed.
+ new ByodFlowTestHelper(this).tearDown();
+
if (ACTION_CHECK_DEVICE_OWNER.equals(getIntent().getAction())) {
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
index 1d23175..7ab8e7e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
@@ -80,6 +80,9 @@
return;
}
+ // Tidy up in case previous run crashed.
+ new ByodFlowTestHelper(this).tearDown();
+
setContentView(R.layout.requesting_bugreport_device_owner);
setInfoResources(R.string.device_owner_requesting_bugreport_tests,
R.string.device_owner_requesting_bugreport_tests_info, 0);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index acd346a..476eb80 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -29,6 +29,7 @@
import android.media.audiofx.AudioEffect;
import android.net.Uri;
import android.nfc.cardemulation.CardEmulation;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.UserHandle;
@@ -67,7 +68,6 @@
new Intent(AlarmClock.ACTION_SET_TIMER),
new Intent(AlarmClock.ACTION_SHOW_ALARMS),
new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
- new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
new Intent(Settings.ACTION_DATE_SETTINGS),
new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
@@ -266,6 +266,11 @@
notForwardedIntentsFromManaged.add(
new Intent(Settings.ACTION_PRINT_SETTINGS));
}
+
+ if (Build.TYPE.equals("user")) {
+ forwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS));
+ }
}
public boolean checkCrossProfileIntentFilters(int flag) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
index eecf9a7..f231b01 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
@@ -110,7 +110,7 @@
Settings.ACTION_DEVICE_INFO_SETTINGS,
Settings.ACTION_PRIVACY_SETTINGS,
Settings.ACTION_DEVICE_INFO_SETTINGS,
- Settings.ACTION_MANAGE_EXTERNAL_SOURCES,
+ Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
Settings.ACTION_SYNC_SETTINGS,
Settings.ACTION_WIRELESS_SETTINGS,
Settings.ACTION_WIRELESS_SETTINGS,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
index 92bb555..f12d698 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
@@ -17,19 +17,20 @@
package com.android.cts.verifier.managedprovisioning;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
-import android.widget.Toast;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
+import android.widget.Toast;
import com.android.cts.verifier.IntentDrivenTestActivity;
import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
-import com.android.cts.verifier.managedprovisioning.ByodHelperActivity;
import com.android.cts.verifier.R;
import com.android.cts.verifier.TestListAdapter.TestListItem;
@@ -58,9 +59,8 @@
static void requestDeleteManagedProfile(Context context) {
try {
Intent intent = new Intent(ByodHelperActivity.ACTION_REMOVE_MANAGED_PROFILE);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
- String message = context.getString(R.string.provisioning_byod_delete_profile);
- Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
catch (ActivityNotFoundException e) {
Log.d(TAG, "requestDeleteProfileOwner: ActivityNotFoundException", e);
@@ -93,4 +93,41 @@
static void showToast(Context context, int messageId) {
Toast.makeText(context, messageId, Toast.LENGTH_SHORT).show();
}
+
+ /**
+ * Prompts the tester to set a screen lock credential, or change it if one exists.
+ *
+ * An instruction dialog is shown before the tester is sent to the ChooseLockGeneric activity
+ * in Settings.
+ *
+ * @param activity The calling activity where the result is handled
+ * @param requestCode The callback request code when the lock is set
+ */
+ static void setScreenLock(Activity activity, int requestCode) {
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.provisioning_byod)
+ .setMessage(R.string.provisioning_byod_set_screen_lock_dialog_message)
+ .setPositiveButton(R.string.go_button_text, (DialogInterface dialog, int which) ->
+ activity.startActivityForResult(intent, requestCode))
+ .show();
+ }
+
+ /**
+ * Prompts the tester to remove the current screen lock credential.
+ *
+ * An instruction dialog is shown before the tester is sent to the ChooseLockGeneric activity
+ * in Settings.
+ *
+ * @param activity The calling activity
+ */
+ static void removeScreenLock(Activity activity) {
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.provisioning_byod)
+ .setMessage(R.string.provisioning_byod_remove_screen_lock_dialog_message)
+ .setPositiveButton(R.string.go_button_text, (DialogInterface dialog, int which) ->
+ activity.startActivity(intent))
+ .show();
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
index 7ecdc30..a73f964 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
@@ -285,12 +285,11 @@
// 6. request network
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
- String networkSpecifier = mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(
- peerHandle) : discoverySession.createNetworkSpecifierPassphrase(peerHandle,
- PASSPHRASE);
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
- networkSpecifier).build();
+ mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(peerHandle)
+ : discoverySession.createNetworkSpecifierPassphrase(peerHandle,
+ PASSPHRASE)).build();
CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
@@ -374,12 +373,11 @@
// 4. Request network
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
- String networkSpecifier = mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(
- peerHandle) : discoverySession.createNetworkSpecifierPassphrase(peerHandle,
- PASSPHRASE);
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
- networkSpecifier).build();
+ mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(peerHandle)
+ : discoverySession.createNetworkSpecifierPassphrase(peerHandle,
+ PASSPHRASE)).build();
CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
index a2e0de5..3dc31e1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
@@ -265,13 +265,13 @@
// 6. Request network (as Responder) and wait for network
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
- String networkSpecifier = mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
- WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac)
- : mWifiAwareSession.createNetworkSpecifierPassphrase(
- WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac, PASSPHRASE);
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
- networkSpecifier).build();
+ mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac)
+ : mWifiAwareSession.createNetworkSpecifierPassphrase(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac,
+ PASSPHRASE)).build();
CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
@@ -397,13 +397,13 @@
// 8. Request network (as Initiator) and wait for network
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
- String networkSpecifier = mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
- WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac)
- : mWifiAwareSession.createNetworkSpecifierPassphrase(
- WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac, PASSPHRASE);
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
- networkSpecifier).build();
+ mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac)
+ : mWifiAwareSession.createNetworkSpecifierPassphrase(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac,
+ PASSPHRASE)).build();
CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
index bc30eefe..792c88a 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
@@ -64,7 +64,11 @@
private void collectFileDetails(DeviceInfoStore store, String path, String suffix)
throws Exception {
File dir = new File(path);
- for (File file : dir.listFiles()) {
+ File[] files = dir.listFiles();
+ if (files == null) {
+ return;
+ }
+ for (File file : files) {
String name = file.getName();
if (file.isFile() && name.endsWith(suffix)) {
String sha1 = "unknown";
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java b/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
new file mode 100644
index 0000000..4ac8403
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A receiver that allows caller to wait for the broadcast synchronously. Notice that you should not
+ * reuse the instance. Usage is typically like this:
+ * <pre>
+ * BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(context, "action");
+ * try {
+ * receiver.register();
+ * Intent intent = receiver.awaitForBroadcast();
+ * // assert the intent
+ * } finally {
+ * receiver.unregisterQuietly();
+ * }
+ * </pre>
+ */
+public class BlockingBroadcastReceiver extends BroadcastReceiver {
+ private static final String TAG = "BlockingBroadcast";
+
+ private static final int DEFAULT_TIMEOUT_SECONDS = 10;
+
+ private final BlockingQueue<Intent> mBlockingQueue;
+ private final String mExpectedAction;
+ private final Context mContext;
+
+ public BlockingBroadcastReceiver(Context context, String expectedAction) {
+ mContext = context;
+ mExpectedAction = expectedAction;
+ mBlockingQueue = new ArrayBlockingQueue<>(1);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mExpectedAction.equals(intent.getAction())) {
+ mBlockingQueue.add(intent);
+ }
+ }
+
+ public void register() {
+ mContext.registerReceiver(this, new IntentFilter(mExpectedAction));
+ }
+
+ /**
+ * Wait until the broadcast and return the received broadcast intent. {@code null} is returned
+ * if no broadcast with expected action is received within 10 seconds.
+ */
+ public @Nullable Intent awaitForBroadcast() {
+ try {
+ return mBlockingQueue.poll(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "waitForBroadcast get interrupted: ", e);
+ }
+ return null;
+ }
+
+ public void unregisterQuietly() {
+ try {
+ mContext.unregisterReceiver(this);
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to unregister BlockingBroadcastReceiver: ", ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
index c63b54a..19278d0 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
@@ -29,13 +29,15 @@
import android.support.test.uiautomator.UiDevice;
import android.util.Log;
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class SilentProvisioningTestManager {
private static final long TIMEOUT_SECONDS = 120L;
- private static final String TAG = "SilentProvisioningTestManager";
+ private static final String TAG = "SilentProvisioningTest";
private final LinkedBlockingQueue<Boolean> mProvisioningResults = new LinkedBlockingQueue(1);
@@ -51,18 +53,14 @@
};
private final Context mContext;
- private final BlockingReceiver mManagedProfileProvisionedReceiver;
- private final BlockingReceiver mManagedProfileAddedReceiver;
+ private Intent mReceivedProfileProvisionedIntent;
public SilentProvisioningTestManager(Context context) {
mContext = context.getApplicationContext();
- mManagedProfileProvisionedReceiver =
- new BlockingReceiver(mContext, ACTION_MANAGED_PROFILE_PROVISIONED);
- mManagedProfileAddedReceiver = new BlockingReceiver(mContext, ACTION_MANAGED_PROFILE_ADDED);
}
public Intent getReceviedProfileProvisionedIntent() {
- return mManagedProfileProvisionedReceiver.getReceivedIntent();
+ return mReceivedProfileProvisionedIntent;
}
public boolean startProvisioningAndWait(Intent provisioningIntent) throws InterruptedException {
@@ -82,23 +80,33 @@
}
private boolean waitManagedProfileProvisioning() throws InterruptedException {
- mManagedProfileProvisionedReceiver.register();
- mManagedProfileAddedReceiver.register();
+ BlockingBroadcastReceiver managedProfileProvisionedReceiver =
+ new BlockingBroadcastReceiver(mContext, ACTION_MANAGED_PROFILE_PROVISIONED);
+ BlockingBroadcastReceiver managedProfileAddedReceiver =
+ new BlockingBroadcastReceiver(mContext, ACTION_MANAGED_PROFILE_ADDED);
+ try {
+ managedProfileProvisionedReceiver.register();
+ managedProfileAddedReceiver.register();
- if (!pollProvisioningResult()) {
- return false;
+ if (!pollProvisioningResult()) {
+ return false;
+ }
+
+ mReceivedProfileProvisionedIntent =
+ managedProfileProvisionedReceiver.awaitForBroadcast();
+ if (mReceivedProfileProvisionedIntent == null) {
+ Log.i(TAG, "managedProfileProvisionedReceiver.awaitForBroadcast(): failed");
+ return false;
+ }
+
+ if (managedProfileAddedReceiver.awaitForBroadcast() == null) {
+ Log.i(TAG, "managedProfileAddedReceiver.awaitForBroadcast(): failed");
+ return false;
+ }
+ } finally {
+ managedProfileProvisionedReceiver.unregisterQuietly();
+ managedProfileAddedReceiver.unregisterQuietly();
}
-
- if (!mManagedProfileProvisionedReceiver.await()) {
- Log.i(TAG, "mManagedProfileProvisionedReceiver.await(): false");
- return false;
- }
-
- if (!mManagedProfileAddedReceiver.await()) {
- Log.i(TAG, "mManagedProfileAddedReceiver.await(): false");
- return false;
- }
-
return true;
}
diff --git a/common/host-side/tradefed/res/report/compatibility_failures.xsl b/common/host-side/tradefed/res/report/compatibility_failures.xsl
index be65b91..ef067f2 100644
--- a/common/host-side/tradefed/res/report/compatibility_failures.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_failures.xsl
@@ -82,12 +82,6 @@
</td>
</tr>
<tr>
- <td class="rowtitle">Tests Not Executed</td>
- <td>
- <xsl:value-of select="Result/Summary/@not_executed"/>
- </td>
- </tr>
- <tr>
<td class="rowtitle">Modules Done</td>
<td>
<xsl:value-of select="Result/Summary/@modules_done"/>
@@ -134,8 +128,8 @@
<th>Module</th>
<th>Passed</th>
<th>Failed</th>
- <th>Not Executed</th>
<th>Total Tests</th>
+ <th>Done</th>
</tr>
<xsl:for-each select="Result/Module">
<tr>
@@ -155,10 +149,10 @@
<xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
</td>
<td>
- <xsl:value-of select="count(TestCase/Test[@result = 'not_executed'])"/>
+ <xsl:value-of select="count(TestCase/Test[@result = 'fail']) + @pass"/>
</td>
<td>
- <xsl:value-of select="count(TestCase/Test[@result = 'fail']) + @pass + count(TestCase/Test[@result = 'not_executed']) "/>
+ <xsl:value-of select="@done"/>
</td>
</tr>
</xsl:for-each> <!-- end Module -->
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsd b/common/host-side/tradefed/res/report/compatibility_result.xsd
index 9b2758c..95bae85 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsd
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsd
@@ -36,7 +36,6 @@
<xs:complexType name="summaryType">
<xs:attribute name="failed" type="xs:integer"/>
- <xs:attribute name="not_executed" type="xs:integer"/>
<xs:attribute name="pass" type="xs:integer"/>
</xs:complexType>
@@ -121,7 +120,6 @@
<xs:restriction base="xs:string">
<xs:enumeration value="pass"/>
<xs:enumeration value="fail"/>
- <xs:enumeration value="not_executed"/>
</xs:restriction>
</xs:simpleType>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
index b8c1245..a0c337a7 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -82,12 +82,6 @@
</td>
</tr>
<tr>
- <td class="rowtitle">Tests Not Executed</td>
- <td>
- <xsl:value-of select="Result/Summary/@not_executed"/>
- </td>
- </tr>
- <tr>
<td class="rowtitle">Modules Done</td>
<td>
<xsl:value-of select="Result/Summary/@modules_done"/>
@@ -134,8 +128,8 @@
<th>Module</th>
<th>Passed</th>
<th>Failed</th>
- <th>Not Executed</th>
<th>Total Tests</th>
+ <th>Done</th>
</tr>
<xsl:for-each select="Result/Module">
<tr>
@@ -150,10 +144,10 @@
<xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
</td>
<td>
- <xsl:value-of select="@not_executed"/>
+ <xsl:value-of select="count(TestCase/Test)"/>
</td>
<td>
- <xsl:value-of select="count(TestCase/Test) + @not_executed"/>
+ <xsl:value-of select="@done"/>
</td>
</tr>
</xsl:for-each> <!-- end Module -->
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index 09fed81..6fe1155 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -18,7 +18,7 @@
import com.android.compatibility.SuiteInfo;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
-import com.android.compatibility.common.tradefed.result.SubPlanCreator;
+import com.android.compatibility.common.tradefed.result.SubPlanHelper;
import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.ResultHandler;
@@ -361,7 +361,6 @@
Integer.toString(i),
Integer.toString(result.countResults(TestStatus.PASS)),
Integer.toString(result.countResults(TestStatus.FAIL)),
- Integer.toString(result.getNotExecuted()),
moduleProgress,
CompatibilityBuildHelper.getDirSuffix(result.getStartTime()),
result.getTestPlan(),
@@ -372,9 +371,8 @@
}
// add the table header to the beginning of the list
- table.add(0, Arrays.asList("Session", "Pass", "Fail", "Not Executed",
- "Modules Complete", "Result Directory", "Test Plan", "Device serial(s)",
- "Build ID", "Product"));
+ table.add(0, Arrays.asList("Session", "Pass", "Fail", "Modules Complete",
+ "Result Directory", "Test Plan", "Device serial(s)", "Build ID", "Product"));
tableFormatter.displayTable(table, new PrintWriter(System.out, true));
} else {
printLine(String.format("No results found"));
@@ -404,7 +402,7 @@
}
private void addSubPlan(String[] flatArgs) {
- SubPlanCreator creator = new SubPlanCreator();
+ SubPlanHelper creator = new SubPlanHelper();
try {
ArgsOptionParser optionParser = new ArgsOptionParser(creator);
optionParser.parse(Arrays.asList(flatArgs));
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 fc57e22..ad7cf47 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
@@ -17,7 +17,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
-import com.android.compatibility.common.tradefed.testtype.CompatibilityTest.RetryType;
+import com.android.compatibility.common.tradefed.util.RetryType;
import com.android.compatibility.common.util.ICaseResult;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.IModuleResult;
@@ -89,8 +89,8 @@
@Option(name = CompatibilityTest.RETRY_TYPE_OPTION,
description = "used with " + CompatibilityTest.RETRY_OPTION
- + ", retry tests of a certain status. Possible values include \"failed\" and "
- + "\"not_executed\".",
+ + ", retry tests of a certain status. Possible values include \"failed\", "
+ + "\"not_executed\", and \"custom\".",
importance = Importance.IF_UNSET)
private RetryType mRetryType = null;
@@ -106,6 +106,9 @@
@Option(name = "use-log-saver", description = "Also saves generated result with log saver")
private boolean mUseLogSaver = false;
+ @Option(name = "compress-logs", description = "Whether logs will be saved with compression")
+ private boolean mCompressLogs = true;
+
private CompatibilityBuildHelper mBuildHelper;
private File mResultDir = null;
private File mLogDir = null;
@@ -368,23 +371,10 @@
public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
mCurrentModuleResult.inProgress(false);
mCurrentModuleResult.addRuntime(elapsedTime);
- if (!mModuleWasDone) {
- // Not executed count now represents an upper-bound for a fix to b/33211104.
- // Only setNotExecuted this number if the module has already been completely executed.
- int testCountDiff = Math.max(mTotalTestsInModule - mCurrentTestNum, 0);
- if (isShardResultReporter()) {
- // reset value, which is added to total count for master shard upon merge
- mCurrentModuleResult.setNotExecuted(testCountDiff);
- } else {
- // increment value for master shard
- mCurrentModuleResult.setNotExecuted(mCurrentModuleResult.getNotExecuted()
- + testCountDiff);
- }
- if (mCanMarkDone) {
- // Only mark module done if status of the invocation allows it (mCanMarkDone) and
- // if module has not already been marked done.
- mCurrentModuleResult.setDone(mCurrentTestNum >= mTotalTestsInModule);
- }
+ if (!mModuleWasDone && mCanMarkDone) {
+ // Only mark module done if status of the invocation allows it (mCanMarkDone) and
+ // if module has not already been marked done.
+ mCurrentModuleResult.setDone(mCurrentTestNum >= mTotalTestsInModule);
}
if (isShardResultReporter()) {
// Forward module results to the master.
@@ -514,6 +504,7 @@
} else {
info("Test Result: %s", resultFile.getCanonicalPath());
}
+ info("Test Logs: %s", mLogDir.getCanonicalPath());
debug("Full Result: %s", zippedResults.getCanonicalPath());
saveLog(resultFile, zippedResults);
@@ -525,11 +516,10 @@
CLog.e(e);
}
// print the run results last.
- info("Invocation finished in %s. PASSED: %d, FAILED: %d, NOT EXECUTED: %d, MODULES: %s",
+ info("Invocation finished in %s. PASSED: %d, FAILED: %d, MODULES: %s",
TimeUtil.formatElapsedTime(elapsedTime),
mResult.countResults(TestStatus.PASS),
mResult.countResults(TestStatus.FAIL),
- mResult.getNotExecuted(),
moduleProgress);
}
@@ -554,7 +544,12 @@
return;
}
try {
- File logFile = mTestLogSaver.saveAndZipLogData(name, type, stream.createInputStream());
+ File logFile = null;
+ if (mCompressLogs) {
+ logFile = mTestLogSaver.saveAndGZipLogData(name, type, stream.createInputStream());
+ } else {
+ logFile = mTestLogSaver.saveLogData(name, type, stream.createInputStream());
+ }
debug("Saved logs for %s in %s", name, logFile.getAbsolutePath());
} catch (IOException e) {
warn("Failed to write log for %s", name);
@@ -677,6 +672,7 @@
return true; // always allow modules to be marked done if not retry
}
return !(RetryType.FAILED.equals(mRetryType)
+ || RetryType.CUSTOM.equals(mRetryType)
|| args.contains(CompatibilityTest.INCLUDE_FILTER_OPTION)
|| args.contains(CompatibilityTest.EXCLUDE_FILTER_OPTION)
|| args.contains(CompatibilityTest.SUBPLAN_OPTION)
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanHelper.java
similarity index 89%
rename from common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
rename to common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanHelper.java
index 9dbbcbb..950a129 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanHelper.java
@@ -33,11 +33,15 @@
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+import com.android.tradefed.util.StreamUtil;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
@@ -50,7 +54,9 @@
/**
* Class for creating subplans from compatibility result XML.
*/
-public class SubPlanCreator {
+public class SubPlanHelper {
+
+ private static final String XML_EXT = ".xml";
// result types
public static final String PASSED = "passed";
@@ -108,22 +114,45 @@
IInvocationResult mResult = null;
/**
- * Create an empty {@link SubPlanCreator}.
+ * Create an empty {@link SubPlanHelper}.
* <p/>
* All {@link Option} fields must be populated via
* {@link com.android.tradefed.config.ArgsOptionParser}
*/
- public SubPlanCreator() {}
+ public SubPlanHelper() {}
/**
- * Create a {@link SubPlanCreator} using the specified option values.
+ * Create a {@link SubPlanHelper} using the specified option values.
*/
- public SubPlanCreator(String name, int session, Collection<String> resultTypes) {
+ public SubPlanHelper(String name, int session, Collection<String> resultTypes) {
mSubPlanName = name;
mSessionId = session;
mResultTypes.addAll(resultTypes);
}
+ public static ISubPlan getSubPlanByName(CompatibilityBuildHelper buildHelper, String name) {
+ if (!name.endsWith(XML_EXT)) {
+ name = name + XML_EXT; // only append XML extension to name if not already there
+ }
+ InputStream subPlanInputStream = null;
+ try {
+ File subPlanFile = new File(buildHelper.getSubPlansDir(), name);
+ if (!subPlanFile.exists()) {
+ throw new IllegalArgumentException(
+ String.format("Could not retrieve subplan \"%s\"", name));
+ }
+ subPlanInputStream = new FileInputStream(subPlanFile);
+ ISubPlan subPlan = new SubPlan();
+ subPlan.parse(subPlanInputStream);
+ return subPlan;
+ } catch (FileNotFoundException | ParseException e) {
+ throw new RuntimeException(
+ String.format("Unable to find or parse subplan %s", name), e);
+ } finally {
+ StreamUtil.closeStream(subPlanInputStream);
+ }
+ }
+
/**
* Set the result from which to derive the subplan.
* @param result
@@ -333,7 +362,7 @@
mSubPlanName = createPlanName();
}
try {
- mSubPlanFile = new File(buildHelper.getSubPlansDir(), mSubPlanName + ".xml");
+ mSubPlanFile = new File(buildHelper.getSubPlansDir(), mSubPlanName + XML_EXT);
if (mSubPlanFile.exists()) {
throw new ConfigurationException(String.format("Subplan %s already exists",
mSubPlanName));
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 30d5f95..41528f1 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -19,15 +19,16 @@
import com.android.compatibility.SuiteInfo;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.InvocationFailureHandler;
-import com.android.compatibility.common.tradefed.result.SubPlanCreator;
+import com.android.compatibility.common.tradefed.result.SubPlanHelper;
import com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker;
import com.android.compatibility.common.tradefed.util.OptionHelper;
+import com.android.compatibility.common.tradefed.util.RetryFilterHelper;
+import com.android.compatibility.common.tradefed.util.RetryType;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.ResultHandler;
import com.android.compatibility.common.util.TestFilter;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.config.ArgsOptionParser;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
@@ -153,10 +154,6 @@
importance = Importance.ALWAYS)
private List<String> mTestArgs = new ArrayList<>();
- public enum RetryType {
- FAILED, NOT_EXECUTED;
- }
-
@Option(name = RETRY_OPTION,
shortName = 'r',
description = "retry a previous session's failed and not executed tests.",
@@ -165,7 +162,7 @@
@Option(name = RETRY_TYPE_OPTION,
description = "used with " + RETRY_OPTION + ", retry tests of a certain status. "
- + "Possible values include \"failed\" and \"not_executed\".",
+ + "Possible values include \"failed\", \"not_executed\", and \"custom\".",
importance = Importance.IF_UNSET)
private RetryType mRetryType = null;
@@ -671,113 +668,45 @@
*/
void setupFilters() throws DeviceNotAvailableException {
if (mRetrySessionId != null) {
- // Track --module/-m and --test/-t options to ensure we don't overwrite non-null
- // values on retry
- String newModuleName = mModuleName;
- String newTestName = mTestName;
-
- // Load the invocation result
- IInvocationResult result = null;
- try {
- result = ResultHandler.findResult(mBuildHelper.getResultsDir(), mRetrySessionId);
- } catch (FileNotFoundException e) {
- throw new RuntimeException(e);
- }
- if (result == null) {
- throw new IllegalArgumentException(String.format(
- "Could not find session with id %d", mRetrySessionId));
- }
-
- String oldBuildFingerprint = result.getBuildFingerprint();
- String currentBuildFingerprint = mDevice.getProperty("ro.build.fingerprint");
- if (oldBuildFingerprint.equals(currentBuildFingerprint)) {
- CLog.logAndDisplay(LogLevel.INFO, "Retrying session from: %s",
- CompatibilityBuildHelper.getDirSuffix(result.getStartTime()));
- } else {
- throw new IllegalArgumentException(String.format(
- "Device build fingerprint must match %s to retry session %d",
- oldBuildFingerprint, mRetrySessionId));
- }
-
- String retryCommandLineArgs = result.getCommandLineArgs();
- if (retryCommandLineArgs != null) {
- try {
- // parse the command-line string from the result file and set options
- ArgsOptionParser parser = new ArgsOptionParser(this);
- parser.parse(OptionHelper.getValidCliArgs(retryCommandLineArgs, this));
- } catch (ConfigurationException e) {
- throw new RuntimeException(e);
- }
- }
-
- if ((mModuleName != null && mModuleName != newModuleName)
- || (mTestName != null && mTestName != newTestName)) {
- // These options cannot be changed on retry if non-null for the previous session
- CLog.w("Cannot override non-null value(s) from session %d for option(s) \"%s\""
- + " or \"%s\" on retry", mRetrySessionId, MODULE_OPTION, TEST_OPTION);
- }
-
- SubPlanCreator retryPlanCreator = new SubPlanCreator();
- retryPlanCreator.setResult(result);
- if (RetryType.FAILED.equals(mRetryType)) {
- // retry only failed tests
- retryPlanCreator.addResultType(SubPlanCreator.FAILED);
- } else if (RetryType.NOT_EXECUTED.equals(mRetryType)){
- // retry only not executed tests
- retryPlanCreator.addResultType(SubPlanCreator.NOT_EXECUTED);
- } else {
- // retry both failed and not executed tests
- retryPlanCreator.addResultType(SubPlanCreator.FAILED);
- retryPlanCreator.addResultType(SubPlanCreator.NOT_EXECUTED);
- }
- try {
- ISubPlan retryPlan = retryPlanCreator.createSubPlan(mBuildHelper);
- mIncludeFilters.addAll(retryPlan.getIncludeFilters());
- mExcludeFilters.addAll(retryPlan.getExcludeFilters());
- } catch (ConfigurationException e) {
- throw new RuntimeException ("Failed to create subplan for retry", e);
- }
- }
- if (mSubPlan != null) {
- try {
- File subPlanFile = new File(mBuildHelper.getSubPlansDir(), mSubPlan + ".xml");
- if (!subPlanFile.exists()) {
- throw new IllegalArgumentException(
- String.format("Could not retrieve subplan \"%s\"", mSubPlan));
- }
- InputStream subPlanInputStream = new FileInputStream(subPlanFile);
- ISubPlan subPlan = new SubPlan();
- subPlan.parse(subPlanInputStream);
+ RetryFilterHelper helper = new RetryFilterHelper(mBuildHelper, mRetrySessionId);
+ helper.validateBuildFingerprint(mDevice);
+ helper.setAllOptionsFrom(this);
+ helper.setCommandLineOptionsFor(this);
+ helper.populateRetryFilters();
+ mIncludeFilters = helper.getIncludeFilters();
+ mExcludeFilters = helper.getExcludeFilters();
+ helper.tearDown();
+ } else {
+ if (mSubPlan != null) {
+ ISubPlan subPlan = SubPlanHelper.getSubPlanByName(mBuildHelper, mSubPlan);
mIncludeFilters.addAll(subPlan.getIncludeFilters());
mExcludeFilters.addAll(subPlan.getExcludeFilters());
- } catch (FileNotFoundException | ParseException e) {
- throw new RuntimeException(
- String.format("Unable to find or parse subplan %s", mSubPlan), e);
}
- }
- if (mModuleName != null) {
- try {
- List<String> modules = ModuleRepo.getModuleNamesMatching(
- mBuildHelper.getTestsDir(), mModuleName);
- if (modules.size() == 0) {
- throw new IllegalArgumentException(
- String.format("No modules found matching %s", mModuleName));
- } else if (modules.size() > 1) {
- throw new IllegalArgumentException(String.format(
- "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
- mModuleName, ArrayUtil.join("\n", modules)));
- } else {
- String module = modules.get(0);
- cleanFilters(mIncludeFilters, module);
- cleanFilters(mExcludeFilters, module);
- mIncludeFilters.add(new TestFilter(mAbiName, module, mTestName).toString());
+ if (mModuleName != null) {
+ try {
+ List<String> modules = ModuleRepo.getModuleNamesMatching(
+ mBuildHelper.getTestsDir(), mModuleName);
+ if (modules.size() == 0) {
+ throw new IllegalArgumentException(
+ String.format("No modules found matching %s", mModuleName));
+ } else if (modules.size() > 1) {
+ throw new IllegalArgumentException(String.format("Multiple modules found"
+ + " matching %s:\n%s\nWhich one did you mean?\n",
+ mModuleName, ArrayUtil.join("\n", modules)));
+ } else {
+ String module = modules.get(0);
+ cleanFilters(mIncludeFilters, module);
+ cleanFilters(mExcludeFilters, module);
+ mIncludeFilters.add(
+ new TestFilter(mAbiName, module, mTestName).toString());
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
}
- } catch (FileNotFoundException e) {
- throw new RuntimeException(e);
+ } else if (mTestName != null) {
+ throw new IllegalArgumentException(
+ "Test name given without module name. Add --module <module-name>");
}
- } else if (mTestName != null) {
- throw new IllegalArgumentException(
- "Test name given without module name. Add --module <module-name>");
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
new file mode 100644
index 0000000..4ff3953
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.result.SubPlanHelper;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
+import com.android.compatibility.common.tradefed.testtype.ISubPlan;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.LightInvocationResult;
+import com.android.compatibility.common.util.ResultHandler;
+import com.android.compatibility.common.util.TestFilter;
+import com.android.tradefed.config.ArgsOptionParser;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionCopier;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.ArrayUtil;
+
+import java.io.FileNotFoundException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper for generating --include-filter and --exclude-filter values on compatibility retry.
+ */
+public class RetryFilterHelper {
+
+ @Option(name = CompatibilityTest.SUBPLAN_OPTION,
+ description = "the subplan to run",
+ importance = Importance.IF_UNSET)
+ protected String mSubPlan;
+
+ @Option(name = CompatibilityTest.INCLUDE_FILTER_OPTION,
+ description = "the include module filters to apply.",
+ importance = Importance.ALWAYS)
+ protected Set<String> mIncludeFilters = new HashSet<>();
+
+ @Option(name = CompatibilityTest.EXCLUDE_FILTER_OPTION,
+ description = "the exclude module filters to apply.",
+ importance = Importance.ALWAYS)
+ protected Set<String> mExcludeFilters = new HashSet<>();
+
+ @Option(name = CompatibilityTest.ABI_OPTION,
+ shortName = 'a',
+ description = "the abi to test.",
+ importance = Importance.IF_UNSET)
+ protected String mAbiName = null;
+
+ @Option(name = CompatibilityTest.MODULE_OPTION,
+ shortName = 'm',
+ description = "the test module to run.",
+ importance = Importance.IF_UNSET)
+ protected String mModuleName = null;
+
+ @Option(name = CompatibilityTest.TEST_OPTION,
+ shortName = CompatibilityTest.TEST_OPTION_SHORT_NAME,
+ description = "the test run.",
+ importance = Importance.IF_UNSET)
+ protected String mTestName = null;
+
+ @Option(name = CompatibilityTest.RETRY_TYPE_OPTION,
+ description = "used with " + CompatibilityTest.RETRY_OPTION
+ + ", retry tests of a certain status. Possible values include \"failed\", "
+ + "\"not_executed\", and \"custom\".",
+ importance = Importance.IF_UNSET)
+ protected RetryType mRetryType = null;
+
+ /* Instance variables handy for retreiving the result to be retried */
+ private CompatibilityBuildHelper mBuild = null;
+ private int mSessionId;
+
+ /* Sets to be populated by retry logic and returned by getter methods */
+ private Set<String> mRetryIncludes;
+ private Set<String> mRetryExcludes;
+
+ /**
+ * Constructor for a {@link RetryFilterHelper}. Requires a CompatibilityBuildHelper for
+ * retrieving previous sessions and the ID of the session to retry.
+ */
+ public RetryFilterHelper(CompatibilityBuildHelper build, int sessionId) {
+ mBuild = build;
+ mSessionId = sessionId;
+ }
+
+ /**
+ * Throws an {@link IllegalArgumentException} if the device build fingerprint doesn't match
+ * the fingerprint recorded in the previous session's result.
+ */
+ public void validateBuildFingerprint(ITestDevice device) throws DeviceNotAvailableException {
+ String oldBuildFingerprint = new LightInvocationResult(getResult()).getBuildFingerprint();
+ String currentBuildFingerprint = device.getProperty("ro.build.fingerprint");
+ if (!oldBuildFingerprint.equals(currentBuildFingerprint)) {
+ throw new IllegalArgumentException(String.format(
+ "Device build fingerprint must match %s to retry session %d",
+ oldBuildFingerprint, mSessionId));
+ }
+ }
+
+ /**
+ * Copy all applicable options from an input object to this instance of RetryFilterHelper.
+ */
+ public void setAllOptionsFrom(Object obj) {
+ clearOptions(); // Remove existing options first
+ OptionCopier.copyOptionsNoThrow(obj, this);
+ }
+
+ /**
+ * Set a single option on this instance of RetryFilterHelper
+ * @throws {@link ConfigurationException} if the option cannot be set.
+ */
+ public void setOption(String option, String value) throws ConfigurationException {
+ OptionSetter setter = new OptionSetter(this);
+ setter.setOptionValue(option, value);
+ }
+
+ /**
+ * Clear all option values of this RetryFilterHelper.
+ */
+ public void clearOptions() {
+ mSubPlan = null;
+ mIncludeFilters = new HashSet<>();
+ mExcludeFilters = new HashSet<>();
+ mModuleName = null;
+ mTestName = null;
+ mRetryType = null;
+ mAbiName = null;
+ }
+
+ /**
+ * Using command-line arguments from the previous session's result, set the input object's
+ * option values to the values applied in the previous session.
+ */
+ public void setCommandLineOptionsFor(Object obj) {
+ // only need light version to retrieve command-line args
+ IInvocationResult result = new LightInvocationResult(getResult());
+ String retryCommandLineArgs = result.getCommandLineArgs();
+ if (retryCommandLineArgs != null) {
+ try {
+ // parse the command-line string from the result file and set options
+ ArgsOptionParser parser = new ArgsOptionParser(obj);
+ parser.parse(OptionHelper.getValidCliArgs(retryCommandLineArgs, obj));
+ } catch (ConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve an instance of the result to retry using the instance variables referencing
+ * the build and the desired session ID. While it is faster to load this result once and
+ * store it as an instance variable, {@link IInvocationResult} objects are large, and
+ * memory is of greater concern.
+ */
+ public IInvocationResult getResult() {
+ IInvocationResult result = null;
+ try {
+ result = ResultHandler.findResult(mBuild.getResultsDir(), mSessionId);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (result == null) {
+ throw new IllegalArgumentException(String.format(
+ "Could not find session with id %d", mSessionId));
+ }
+ return result;
+ }
+
+ /**
+ * Populate mRetryIncludes and mRetryExcludes based on the options and the result set for
+ * this instance of RetryFilterHelper.
+ */
+ public void populateRetryFilters() {
+ mRetryIncludes = new HashSet<>(mIncludeFilters); // reset for each population
+ mRetryExcludes = new HashSet<>(mExcludeFilters); // reset for each population
+ if (RetryType.CUSTOM.equals(mRetryType)) {
+ Set<String> customIncludes = new HashSet<>(mIncludeFilters);
+ Set<String> customExcludes = new HashSet<>(mExcludeFilters);
+ if (mSubPlan != null) {
+ ISubPlan retrySubPlan = SubPlanHelper.getSubPlanByName(mBuild, mSubPlan);
+ customIncludes.addAll(retrySubPlan.getIncludeFilters());
+ customExcludes.addAll(retrySubPlan.getExcludeFilters());
+ }
+ // If includes were added, only use those includes. Also use excludes added directly
+ // or by subplan. Otherwise, default to normal retry.
+ if (!customIncludes.isEmpty()) {
+ mRetryIncludes.clear();
+ mRetryIncludes.addAll(customIncludes);
+ mRetryExcludes.addAll(customExcludes);
+ return;
+ }
+ }
+ // remove any extra filtering options
+ // TODO(aaronholden) remove non-plan includes (e.g. those in cts-vendor-interface)
+ // TODO(aaronholden) remove non-known-failure excludes
+ mModuleName = null;
+ mTestName = null;
+ mSubPlan = null;
+ populateFiltersBySubPlan();
+ populatePreviousSessionFilters();
+ }
+
+ /* Generation of filters based on previous sessions is implemented thoroughly in SubPlanHelper,
+ * and retry filter generation is just a subset of the use cases for the subplan retry logic.
+ * Use retry type to determine which result types SubPlanHelper targets. */
+ private void populateFiltersBySubPlan() {
+ SubPlanHelper retryPlanCreator = new SubPlanHelper();
+ retryPlanCreator.setResult(getResult());
+ if (RetryType.FAILED.equals(mRetryType)) {
+ // retry only failed tests
+ retryPlanCreator.addResultType(SubPlanHelper.FAILED);
+ } else if (RetryType.NOT_EXECUTED.equals(mRetryType)){
+ // retry only not executed tests
+ retryPlanCreator.addResultType(SubPlanHelper.NOT_EXECUTED);
+ } else {
+ // retry both failed and not executed tests
+ retryPlanCreator.addResultType(SubPlanHelper.FAILED);
+ retryPlanCreator.addResultType(SubPlanHelper.NOT_EXECUTED);
+ }
+ try {
+ ISubPlan retryPlan = retryPlanCreator.createSubPlan(mBuild);
+ mRetryIncludes.addAll(retryPlan.getIncludeFilters());
+ mRetryExcludes.addAll(retryPlan.getExcludeFilters());
+ } catch (ConfigurationException e) {
+ throw new RuntimeException ("Failed to create subplan for retry", e);
+ }
+ }
+
+ /* Retrieves the options set via command-line on the previous session, and generates/adds
+ * filters accordingly */
+ private void populatePreviousSessionFilters() {
+ // Temporarily store options from this instance in another instance
+ RetryFilterHelper tmpHelper = new RetryFilterHelper(mBuild, mSessionId);
+ tmpHelper.setAllOptionsFrom(this);
+ // Copy command-line args from previous session to this RetryFilterHelper's options
+ setCommandLineOptionsFor(this);
+
+ mRetryIncludes.addAll(mIncludeFilters);
+ mRetryExcludes.addAll(mExcludeFilters);
+ if (mSubPlan != null) {
+ ISubPlan retrySubPlan = SubPlanHelper.getSubPlanByName(mBuild, mSubPlan);
+ mRetryIncludes.addAll(retrySubPlan.getIncludeFilters());
+ mRetryExcludes.addAll(retrySubPlan.getExcludeFilters());
+ }
+ if (mModuleName != null) {
+ try {
+ List<String> modules = ModuleRepo.getModuleNamesMatching(
+ mBuild.getTestsDir(), mModuleName);
+ if (modules.size() == 0) {
+ throw new IllegalArgumentException(
+ String.format("No modules found matching %s", mModuleName));
+ } else if (modules.size() > 1) {
+ throw new IllegalArgumentException(String.format(
+ "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
+ mModuleName, ArrayUtil.join("\n", modules)));
+ } else {
+ String module = modules.get(0);
+ cleanFilters(mRetryIncludes, module);
+ cleanFilters(mRetryExcludes, module);
+ mRetryIncludes.add(new TestFilter(mAbiName, module, mTestName).toString());
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ } else if (mTestName != null) {
+ throw new IllegalArgumentException(
+ "Test name given without module name. Add --module <module-name>");
+ }
+
+ // Copy options for current session back to this instance
+ setAllOptionsFrom(tmpHelper);
+ }
+
+ /* Helper method designed to remove filters in a list not applicable to the given module */
+ private static void cleanFilters(Set<String> filters, String module) {
+ Set<String> cleanedFilters = new HashSet<String>();
+ for (String filter : filters) {
+ if (module.equals(TestFilter.createFrom(filter).getName())) {
+ cleanedFilters.add(filter); // Module name matches, filter passes
+ }
+ }
+ filters.clear();
+ filters.addAll(cleanedFilters);
+ }
+
+ /** Retrieve include filters to be applied on retry */
+ public Set<String> getIncludeFilters() {
+ return new HashSet<>(mRetryIncludes);
+ }
+
+ /** Retrieve exclude filters to be applied on retry */
+ public Set<String> getExcludeFilters() {
+ return new HashSet<>(mRetryExcludes);
+ }
+
+ /** Clears retry filters and internal storage of options, except buildInfo and session ID */
+ public void tearDown() {
+ clearOptions();
+ mRetryIncludes = null;
+ mRetryExcludes = null;
+ // keep references to buildInfo and session ID
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryType.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryType.java
new file mode 100644
index 0000000..b5d3cd5
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryType.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+/**
+ * Enum for --retry-type option value in compatibility testing.
+ */
+public enum RetryType {
+ FAILED,
+ NOT_EXECUTED,
+ CUSTOM;
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index bb96ed2..b6861db 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -25,7 +25,7 @@
import com.android.compatibility.common.tradefed.result.ConsoleReporterTest;
import com.android.compatibility.common.tradefed.result.MetadataReporterTest;
import com.android.compatibility.common.tradefed.result.ResultReporterTest;
-import com.android.compatibility.common.tradefed.result.SubPlanCreatorTest;
+import com.android.compatibility.common.tradefed.result.SubPlanHelperTest;
import com.android.compatibility.common.tradefed.targetprep.PropertyCheckTest;
import com.android.compatibility.common.tradefed.targetprep.SettingsPreparerTest;
import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBaseTest;
@@ -36,6 +36,7 @@
import com.android.compatibility.common.tradefed.testtype.SubPlanTest;
import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
import com.android.compatibility.common.tradefed.util.OptionHelperTest;
+import com.android.compatibility.common.tradefed.util.RetryFilterHelperTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -67,7 +68,7 @@
ConsoleReporterTest.class,
MetadataReporterTest.class,
ResultReporterTest.class,
- SubPlanCreatorTest.class,
+ SubPlanHelperTest.class,
// targetprep
PropertyCheckTest.class,
@@ -84,6 +85,7 @@
// util
CollectorUtilTest.class,
OptionHelperTest.class,
+ RetryFilterHelperTest.class,
})
public class UnitTests {
// empty on purpose
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
index c8896a96..8ef909e 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
@@ -185,7 +185,6 @@
mReporter.invocationEnded(500);
EasyMock.verify(mMockDevice, mMockBuildInfo);
IInvocationResult result = mReporter.getResult();
- assertEquals(0, result.getNotExecuted());
assertEquals(2, result.countResults(TestStatus.PASS));
assertEquals(1, result.countResults(TestStatus.FAIL));
assertEquals(1, result.getModules().size());
@@ -212,7 +211,6 @@
mReporter.invocationEnded(500);
EasyMock.verify(mMockDevice, mMockBuildInfo);
IInvocationResult result = mReporter.getResult();
- assertEquals(1, result.getNotExecuted());
assertEquals(1, result.countResults(TestStatus.PASS));
assertEquals(1, result.countResults(TestStatus.FAIL));
// Module should not be seen as complete.
@@ -243,7 +241,6 @@
EasyMock.verify(mMockDevice, mMockBuildInfo);
IInvocationResult result = mReporter.getResult();
// FIXME: All tests should be marked as executed and not aggregating the count.
- assertEquals(3, result.getNotExecuted());
assertEquals(2, result.countResults(TestStatus.PASS));
assertEquals(1, result.countResults(TestStatus.FAIL));
// FIXME: Module should be complete since all its test have run.
@@ -283,7 +280,6 @@
mReporter.invocationEnded(500);
IInvocationResult result = mReporter.getResult();
- assertEquals(1, result.getNotExecuted());
assertEquals(1, result.countResults(TestStatus.PASS));
assertEquals(1, result.countResults(TestStatus.FAIL));
// Module should not be seen as complete.
@@ -313,7 +309,6 @@
result = mReporter.getResult();
// FIXME: We should only have 1 not_executed in the retry too. They should not aggregate
// from one run to another.
- assertEquals(2, result.getNotExecuted());
assertEquals(1, result.countResults(TestStatus.PASS));
assertEquals(1, result.countResults(TestStatus.FAIL));
// Module should not be seen as complete.
@@ -352,7 +347,6 @@
mReporter.invocationEnded(500);
IInvocationResult result = mReporter.getResult();
- assertEquals(1, result.getNotExecuted());
assertEquals(1, result.countResults(TestStatus.PASS));
assertEquals(1, result.countResults(TestStatus.FAIL));
// Module should not be seen as complete.
@@ -386,7 +380,6 @@
// Check retry results
result = mReporter.getResult();
- assertEquals(0, result.getNotExecuted());
assertEquals(3, result.countResults(TestStatus.PASS));
assertEquals(0, result.countResults(TestStatus.FAIL));
// Module should be marked as complete after retry.
@@ -489,7 +482,6 @@
EasyMock.verify(mMockDevice, mMockBuildInfo);
// Check aggregated results to make sure it's consistent.
IInvocationResult result = mReporter.getResult();
- assertEquals(0, result.getNotExecuted());
assertEquals(4, result.countResults(TestStatus.PASS));
assertEquals(4, result.countResults(TestStatus.FAIL));
assertEquals(2, result.getModules().size());
@@ -540,7 +532,6 @@
EasyMock.verify(mMockDevice, mMockBuildInfo);
// Check aggregated results to make sure it's consistent.
IInvocationResult result = mReporter.getResult();
- assertEquals(4, result.getNotExecuted());
assertEquals(4, result.countResults(TestStatus.PASS));
assertEquals(4, result.countResults(TestStatus.FAIL));
assertEquals(2, result.getModules().size());
@@ -592,7 +583,6 @@
EasyMock.verify(mMockDevice, mMockBuildInfo);
IInvocationResult result = mReporter.getResult();
- assertEquals(0, result.getNotExecuted());
assertEquals(2, result.countResults(TestStatus.PASS));
assertEquals(2, result.countResults(TestStatus.FAIL));
// FIXME: Only one module should be expected since within the one shard requested to run
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
index 763acb7..23fcb9a 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
@@ -93,7 +93,6 @@
mInvocationResult = resultReporter.getResult();
mModuleResult = mInvocationResult.getOrCreateModule("Module-1");
mModuleResult.setDone(true);
- mModuleResult.setNotExecuted(0);
ICaseResult caseResult = mModuleResult.getOrCreateResult("Case-1");
ITestResult test1 = caseResult.getOrCreateResult("Test1");
test1.passed(mReportLog);
@@ -103,7 +102,6 @@
IModuleResult moduleResult2 = mInvocationResult.getOrCreateModule("Module-2");
ICaseResult caseResult2 = moduleResult2.getOrCreateResult("Case-2");
mModuleResult.setDone(false);
- mModuleResult.setNotExecuted(1);
ITestResult test3 = caseResult2.getOrCreateResult("Test3");
test3.passed(mReportLog);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
similarity index 96%
rename from common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
rename to common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
index e3240c1..db6ca6e 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
@@ -39,7 +39,7 @@
import java.util.Arrays;
import java.util.Set;
-public class SubPlanCreatorTest extends TestCase {
+public class SubPlanHelperTest extends TestCase {
// Values used to populate mock results
private static final String SUITE_NAME = "CTS";
@@ -75,7 +75,7 @@
private static final String SP_RESULT_TYPE_NOT_EXECUTED = "not_executed";
private CompatibilityBuildHelper mBuildHelper;
- private SubPlanCreator mSubPlanCreator;
+ private SubPlanHelper mSubPlanHelper;
private File mResultsDir = null;
private File mResultDir = null;
@@ -89,8 +89,8 @@
mBuildHelper = new SpctMockCompatibilityBuildHelper(new BuildInfo("0", "", ""));
populateResults();
- mSubPlanCreator = new SubPlanCreator();
- ArgsOptionParser optionParser = new ArgsOptionParser(mSubPlanCreator);
+ mSubPlanHelper = new SubPlanHelper();
+ ArgsOptionParser optionParser = new ArgsOptionParser(mSubPlanHelper);
optionParser.parse(Arrays.asList(
"-n", SP_NAME,
"--session", SP_SESSION,
@@ -109,7 +109,7 @@
}
public void testCreateSubPlan() throws Exception {
- ISubPlan plan = mSubPlanCreator.createSubPlan(mBuildHelper);
+ ISubPlan plan = mSubPlanHelper.createSubPlan(mBuildHelper);
Set<String> planIncludes = plan.getIncludeFilters();
Set<String> planExcludes = plan.getExcludeFilters();
TestFilter mf1 = new TestFilter(ABI, NAME_A, null);
@@ -137,7 +137,6 @@
moduleATest1.setResultStatus(TestStatus.PASS);
ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
moduleATest2.setResultStatus(null); // not executed test
- moduleA.setNotExecuted(1);
IModuleResult moduleB = result.getOrCreateModule(ID_B);
moduleB.setDone(true);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/RetryFilterHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/RetryFilterHelperTest.java
new file mode 100644
index 0000000..05d35ec
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/RetryFilterHelperTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.tradefed.config.OptionSetter;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link RetryFilterHelper}
+ */
+public class RetryFilterHelperTest extends TestCase {
+
+ private static final String TEST_STRING = "abcd";
+ private static final RetryType TEST_RETRY_TYPE = RetryType.FAILED;
+
+ public void testSetAllOptionsFrom() throws Exception {
+ RetryFilterHelper helper = new RetryFilterHelper(null, 0);
+ RetryFilterHelper otherObj = new RetryFilterHelper(null, 0);
+ OptionSetter otherObjSetter = new OptionSetter(otherObj);
+ otherObjSetter.setOptionValue(CompatibilityTest.SUBPLAN_OPTION, TEST_STRING);
+ helper.setAllOptionsFrom(otherObj);
+ assertEquals(TEST_STRING, helper.mSubPlan);
+ }
+
+ public void testClearOptions() throws Exception {
+ RetryFilterHelper helper = new RetryFilterHelper(null, 0);
+ OptionSetter setter = new OptionSetter(helper);
+ setter.setOptionValue(CompatibilityTest.SUBPLAN_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.INCLUDE_FILTER_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.EXCLUDE_FILTER_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.ABI_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.MODULE_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.TEST_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.TEST_OPTION, TEST_RETRY_TYPE.name());
+ helper.clearOptions();
+ assertTrue(helper.mSubPlan == null);
+ assertTrue(helper.mIncludeFilters.isEmpty());
+ assertTrue(helper.mExcludeFilters.isEmpty());
+ assertTrue(helper.mAbiName == null);
+ assertTrue(helper.mModuleName == null);
+ assertTrue(helper.mTestName == null);
+ assertTrue(helper.mRetryType == null);
+ }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java b/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
index 32fa532..ce39f38 100644
--- a/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
+++ b/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
@@ -331,7 +331,6 @@
sb.append(buildFingerprint).append(SEPARATOR)
.append(module.getId()).append(SEPARATOR)
.append(module.isDone()).append(SEPARATOR)
- .append(module.getNotExecuted()).append(SEPARATOR)
.append(module.countResults(TestStatus.FAIL));
return sb.toString();
}
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index 6306287..5f88bcd 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -93,7 +93,6 @@
private static final String MODULES_DONE_ATTR = "modules_done";
private static final String MODULES_TOTAL_ATTR = "modules_total";
private static final String NAME_ATTR = "name";
- private static final String NOT_EXECUTED_ATTR = "not_executed";
private static final String OS_ARCH_ATTR = "os_arch";
private static final String OS_NAME_ATTR = "os_name";
private static final String OS_VERSION_ATTR = "os_version";
@@ -210,9 +209,6 @@
boolean done = Boolean.parseBoolean(parser.getAttributeValue(NS, DONE_ATTR));
IModuleResult module = invocation.getOrCreateModule(moduleId);
module.initializeDone(done);
- int notExecuted = Integer.parseInt(
- parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
- module.setNotExecuted(notExecuted);
long runtime = Long.parseLong(parser.getAttributeValue(NS, RUNTIME_ATTR));
module.addRuntime(runtime);
while (parser.nextTag() == XmlPullParser.START_TAG) {
@@ -300,7 +296,6 @@
throws IOException, XmlPullParserException {
int passed = result.countResults(TestStatus.PASS);
int failed = result.countResults(TestStatus.FAIL);
- int notExecuted = result.getNotExecuted();
File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
OutputStream stream = new FileOutputStream(resultFile);
XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
@@ -371,7 +366,6 @@
serializer.startTag(NS, SUMMARY_TAG);
serializer.attribute(NS, PASS_ATTR, Integer.toString(passed));
serializer.attribute(NS, FAILED_ATTR, Integer.toString(failed));
- serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(notExecuted));
serializer.attribute(NS, MODULES_DONE_ATTR,
Integer.toString(result.getModuleCompleteCount()));
serializer.attribute(NS, MODULES_TOTAL_ATTR,
@@ -385,7 +379,6 @@
serializer.attribute(NS, ABI_ATTR, module.getAbi());
serializer.attribute(NS, RUNTIME_ATTR, String.valueOf(module.getRuntime()));
serializer.attribute(NS, DONE_ATTR, Boolean.toString(module.isDone()));
- serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(module.getNotExecuted()));
serializer.attribute(NS, PASS_ATTR,
Integer.toString(module.countResults(TestStatus.PASS)));
for (ICaseResult cr : module.getResults()) {
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 4035dd3..49c4045 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -49,8 +49,6 @@
private static final String NAME_B = "ModuleB";
private static final String DONE_A = "false";
private static final String DONE_B = "true";
- private static final String NOT_EXECUTED_A = "1";
- private static final String NOT_EXECUTED_B = "0";
private static final String RUNTIME_A = "100";
private static final String RUNTIME_B = "200";
private static final String ABI = "mips64";
@@ -105,10 +103,10 @@
" <Build build_fingerprint=\"%s\" " + BUILD_ID + "=\"%s\" " +
BUILD_PRODUCT + "=\"%s\" />\n";
private static final String XML_SUMMARY =
- " <Summary pass=\"%d\" failed=\"%d\" not_executed=\"%d\" " +
+ " <Summary pass=\"%d\" failed=\"%d\" " +
"modules_done=\"1\" modules_total=\"1\" />\n";
private static final String XML_MODULE =
- " <Module name=\"%s\" abi=\"%s\" device=\"%s\" runtime=\"%s\" done=\"%s\" not_executed=\"%s\">\n" +
+ " <Module name=\"%s\" abi=\"%s\" device=\"%s\" runtime=\"%s\" done=\"%s\">\n" +
"%s" +
" </Module>\n";
private static final String XML_CASE =
@@ -167,7 +165,6 @@
moduleATest1.setResultStatus(TestStatus.PASS);
ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
moduleATest2.setResultStatus(null); // not executed test
- moduleA.setNotExecuted(1);
// Module B: test3 fails, test4 passes with report log, test5 passes with skip
IModuleResult moduleB = result.getOrCreateModule(ID_B);
moduleB.setDone(true);
@@ -231,7 +228,7 @@
String moduleATest = String.format(XML_TEST_PASS, METHOD_1);
String moduleACases = String.format(XML_CASE, CLASS_A, moduleATest);
String moduleA = String.format(XML_MODULE, NAME_A, ABI, DEVICE_A, RUNTIME_A, DONE_A,
- NOT_EXECUTED_A, moduleACases);
+ moduleACases);
String moduleBTest3 = String.format(XML_TEST_FAIL, METHOD_3, MESSAGE, STACK_TRACE,
BUG_REPORT, LOGCAT, SCREENSHOT);
String moduleBTest4 = String.format(XML_TEST_RESULT, METHOD_4, SUMMARY_SOURCE,
@@ -241,7 +238,7 @@
String moduleBTests = String.join("", moduleBTest3, moduleBTest4, moduleBTest5);
String moduleBCases = String.format(XML_CASE, CLASS_B, moduleBTests);
String moduleB = String.format(XML_MODULE, NAME_B, ABI, DEVICE_B, RUNTIME_B, DONE_B,
- NOT_EXECUTED_B, moduleBCases);
+ moduleBCases);
String modules = String.join("", moduleA, moduleB);
String hostName = "";
try {
@@ -265,7 +262,6 @@
static void checkLightResult(IInvocationResult lightResult) throws Exception {
assertEquals("Expected 3 passes", 3, lightResult.countResults(TestStatus.PASS));
assertEquals("Expected 1 failure", 1, lightResult.countResults(TestStatus.FAIL));
- assertEquals("Expected 1 not executed", 1, lightResult.getNotExecuted());
Map<String, String> buildInfo = lightResult.getInvocationInfo();
assertEquals("Incorrect Build ID", EXAMPLE_BUILD_ID, buildInfo.get(BUILD_ID));
@@ -287,7 +283,6 @@
static void checkResult(IInvocationResult result) throws Exception {
assertEquals("Expected 3 passes", 3, result.countResults(TestStatus.PASS));
assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL));
- assertEquals("Expected 1 not executed", 1, result.getNotExecuted());
Map<String, String> buildInfo = result.getInvocationInfo();
assertEquals("Incorrect Build ID", EXAMPLE_BUILD_ID, buildInfo.get(BUILD_ID));
diff --git a/development/ide/eclipse/cts-tradefed-harness.classpath b/development/ide/eclipse/cts-tradefed-harness.classpath
new file mode 100644
index 0000000..3355a7d
--- /dev/null
+++ b/development/ide/eclipse/cts-tradefed-harness.classpath
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="cts/common/host-side/tradefed/src"/>
+ <classpathentry kind="src" path="cts/common/host-side/util/src"/>
+ <classpathentry kind="src" path="cts/common/util/src"/>
+ <classpathentry kind="src" path="cts/libs/json/src"/>
+ <classpathentry kind="src" path="tools/loganalysis/src"/>
+ <classpathentry kind="src" path="tools/tradefederation/src"/>
+ <classpathentry kind="src" path="tools/tradefederation/remote/src"/>
+ <classpathentry kind="src" path="external/easymock/src"/>
+ <classpathentry kind="src" path="external/guava/guava/src"/>
+ <classpathentry kind="src" path="external/hamcrest/hamcrest-core/src/main/java"/>
+ <classpathentry kind="src" path="external/jline/src/src/main/java"/>
+ <classpathentry kind="src" path="external/jsr305/ri/src/main/java"/>
+ <classpathentry kind="src" path="external/junit/src/main/java"/>
+ <classpathentry kind="src" path="external/mockito/src/main/java"/>
+ <classpathentry kind="src" path="external/objenesis/main/src/main/java"/>
+ <classpathentry kind="src" path="external/protobuf/java/core/src/main/java"/>
+ <classpathentry including="com/" kind="src" path="out/host/common/obj/JAVA_LIBRARIES/cts-tradefed_intermediates"/>
+ <classpathentry kind="src" path="out/host/common/obj/JAVA_LIBRARIES/host-libprotobuf-java-full_intermediates/proto/src"/>
+ <classpathentry kind="src" path="out/host/common/obj/JAVA_LIBRARIES/tradefed-protos_intermediates/proto/src"/>
+ <classpathentry kind="src" path="tools/tradefederation/tests/src"/>
+ <classpathentry kind="src" path="cts/common/host-side/tradefed/tests/src"/>
+ <classpathentry kind="src" path="cts/common/host-side/util/tests/src"/>
+ <classpathentry kind="lib" path="external/mockito/lib/byte-buddy-1.6.9.jar"/>
+ <classpathentry kind="lib" path="external/mockito/lib/byte-buddy-agent-1.6.9.jar"/>
+ <classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/bouncycastle_intermediates/classes-jarjar.jar"/>
+ <classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/conscrypt_intermediates/classes-jarjar.jar"/>
+ <classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/okhttp_intermediates/classes-jarjar.jar"/>
+ <classpathentry kind="lib" path="prebuilts/misc/common/commons-compress/commons-compress-prebuilt.jar"/>
+ <classpathentry kind="lib" path="prebuilts/misc/common/ddmlib/ddmlib-prebuilt.jar"/>
+ <classpathentry kind="lib" path="prebuilts/misc/common/devtools-annotations/devtools-annotations-prebuilt.jar"/>
+ <classpathentry kind="lib" path="prebuilts/misc/common/json/json-prebuilt.jar"/>
+ <classpathentry kind="lib" path="prebuilts/misc/common/kxml2/kxml2-2.3.0.jar"/>
+ <classpathentry kind="lib" path="prebuilts/misc/common/sdklib/sdklib-prebuilt.jar"/>
+ <classpathentry kind="lib" path="prebuilts/sdk/tools/jack-jacoco-reporter.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 6ee51ae..e8dca57 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -291,29 +291,34 @@
final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
- enableWriteSettings(WRITE_PKG);
- runDeviceTests(
- WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", users[0]);
-
assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
for (int user : users) {
+ enableWriteSettings(WRITE_PKG, user);
+ runDeviceTests(
+ WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", user);
+
runDeviceTests(
NONE_PKG, NONE_PKG + ".ReadDefaultUris", "testPlayDefaultUris", user);
}
} finally {
// Make sure the provider and uris are reset on failure.
- runDeviceTests(
- WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testResetDefaultUris", users[0]);
+ for (int user : users) {
+ runDeviceTests(
+ WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testResetDefaultUris", user);
+ }
getDevice().uninstallPackage(NONE_PKG);
getDevice().uninstallPackage(WRITE_PKG);
removeUsersForTest(users);
}
}
- private void enableWriteSettings(String packageName) throws DeviceNotAvailableException {
+ private void enableWriteSettings(String packageName, int userId)
+ throws DeviceNotAvailableException {
StringBuilder cmd = new StringBuilder();
- cmd.append("appops set ");
+ cmd.append("appops set --user ");
+ cmd.append(userId);
+ cmd.append(" ");
cmd.append(packageName);
cmd.append(" android:write_settings allow");
getDevice().executeShellCommand(cmd.toString());
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
index 3b6cbb1..cf8a354 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -64,6 +64,11 @@
getDevice().uninstallPackage(PKG);
}
+ public void testUsesLibrary() throws Exception {
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
+ runDeviceTests(PKG, ".UsesLibraryTest", "testUsesLibrary");
+ }
+
public void testMissingLibrary() throws Exception {
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
runDeviceTests(PKG, ".UsesLibraryTest", "testMissingLibrary");
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
index a047732..15197a0 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
@@ -92,8 +92,6 @@
mDevice.waitForIdle();
// Set a PIN for this user
- mDevice.executeShellCommand("settings put global require_password_to_decrypt 0");
- mDevice.executeShellCommand("locksettings set-disabled false");
mDevice.executeShellCommand("locksettings set-pin 12345");
}
@@ -107,8 +105,6 @@
// Clear PIN for this user
mDevice.executeShellCommand("locksettings clear --old 12345");
- mDevice.executeShellCommand("locksettings set-disabled true");
- mDevice.executeShellCommand("settings delete global require_password_to_decrypt");
}
public void doBootCountBefore() throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
index e591c25..63caebc 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
@@ -63,6 +63,7 @@
android:theme="@android:style/Theme.NoDisplay">
<!-- TEST: ephemeral apps can start this activity using directed intent -->
</activity>
+
<service
android:name=".EphemeralService">
<!-- TEST: ephemeral apps can see this service using query methods -->
@@ -76,6 +77,15 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
+
+ <provider
+ android:name=".EphemeralProvider"
+ android:authorities="com.android.cts.ephemeralapp1.provider"
+ android:exported="true">
+ <intent-filter android:priority="0">
+ <action android:name="com.android.cts.ephemeraltest.QUERY" />
+ </intent-filter>
+ </provider>
</application>
<instrumentation
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
index ada9c36..c0f4d2b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
+import android.annotation.Nullable;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -32,6 +33,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
@@ -135,6 +137,53 @@
@Test
public void testQuery() throws Exception {
+ // query normal activities
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(2));
+ assertThat(resolveInfo.get(0).activityInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).activityInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralActivity"));
+ assertThat(resolveInfo.get(0).instantAppAvailable,
+ is(true));
+ assertThat(resolveInfo.get(1).activityInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(1).activityInfo.name,
+ is("com.android.cts.normalapp.ExposedActivity"));
+ assertThat(resolveInfo.get(1).instantAppAvailable,
+ is(false));
+ }
+
+ // query normal activities; directed package
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(2));
+ assertThat(resolveInfo.get(0).activityInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).activityInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralActivity"));
+ assertThat(resolveInfo.get(0).instantAppAvailable,
+ is(true));
+ assertThat(resolveInfo.get(1).activityInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(1).activityInfo.name,
+ is("com.android.cts.normalapp.ExposedActivity"));
+ assertThat(resolveInfo.get(1).instantAppAvailable,
+ is(false));
+ }
+
+ // query normal activities; directed component
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
@@ -176,6 +225,93 @@
assertThat(resolveInfo.get(1).instantAppAvailable,
is(false));
}
+
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setPackage("com.android.cts.ephemeralapp1");
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+ .getContext().getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(1));
+ assertThat(resolveInfo.get(0).serviceInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).serviceInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralService"));
+ }
+
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setComponent(
+ new ComponentName("com.android.cts.ephemeralapp1",
+ "com.android.cts.ephemeralapp1.EphemeralService"));
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+ .getContext().getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(1));
+ assertThat(resolveInfo.get(0).serviceInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).serviceInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralService"));
+ }
+
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+ .getContext().getPackageManager().queryIntentContentProviders(
+ queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(2));
+ assertThat(resolveInfo.get(0).providerInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).providerInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralProvider"));
+ assertThat(resolveInfo.get(1).providerInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(1).providerInfo.name,
+ is("com.android.cts.normalapp.ExposedProvider"));
+ assertThat(resolveInfo.get(1).instantAppAvailable,
+ is(false));
+ }
+
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setPackage("com.android.cts.ephemeralapp1");
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+ .getContext().getPackageManager().queryIntentContentProviders(
+ queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(1));
+ assertThat(resolveInfo.get(0).providerInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).providerInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralProvider"));
+ }
+
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setComponent(
+ new ComponentName("com.android.cts.ephemeralapp1",
+ "com.android.cts.ephemeralapp1.EphemeralProvider"));
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+ .getContext().getPackageManager().queryIntentContentProviders(
+ queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(1));
+ assertThat(resolveInfo.get(0).providerInfo.packageName,
+ is("com.android.cts.ephemeralapp1"));
+ assertThat(resolveInfo.get(0).providerInfo.name,
+ is("com.android.cts.ephemeralapp1.EphemeralProvider"));
+ }
}
@Test
@@ -230,6 +366,48 @@
// provide any feedback. The alternative is to wait for the broadcast timeout
// but it's silly to artificially slow down CTS. We'll rely on queryIntentService
// to check whether or not the service is actually exposed
+
+ // bind to the normal service; directed package
+ {
+ final Intent startNormalIntent = new Intent(ACTION_START_NORMAL);
+ startNormalIntent.setPackage("com.android.cts.normalapp");
+ final TestServiceConnection connection = new TestServiceConnection();
+ try {
+ assertThat(InstrumentationRegistry.getContext().bindService(
+ startNormalIntent, connection, Context.BIND_AUTO_CREATE /*flags*/),
+ is(false));
+ } finally {
+ InstrumentationRegistry.getContext().unbindService(connection);
+ }
+ }
+
+ // bind to the normal service; directed component
+ {
+ final Intent startNormalIntent = new Intent(ACTION_START_NORMAL);
+ startNormalIntent.setComponent(new ComponentName(
+ "com.android.cts.normalapp", "com.android.cts.normalapp.NormalService"));
+ final TestServiceConnection connection = new TestServiceConnection();
+ try {
+ assertThat(InstrumentationRegistry.getContext().bindService(
+ startNormalIntent, connection, Context.BIND_AUTO_CREATE /*flags*/),
+ is(false));
+ } finally {
+ InstrumentationRegistry.getContext().unbindService(connection);
+ }
+ }
+
+ // connect to the normal provider
+ {
+ final String provider = "content://com.android.cts.normalapp.provider/table";
+ final Cursor testCursor = InstrumentationRegistry
+ .getContext().getContentResolver().query(
+ Uri.parse(provider),
+ null /*projection*/,
+ null /*selection*/,
+ null /*selectionArgs*/,
+ null /*sortOrder*/);
+ assertThat(testCursor, is(nullValue()));
+ }
}
@Test
@@ -376,12 +554,43 @@
is("onBind"));
assertThat(testResult.getStatus(),
is("PASS"));
+ assertThat(testResult.getEphemeralPackageInfoExposed(),
+ is(true));
assertThat(testResult.getException(),
is(nullValue()));
} finally {
InstrumentationRegistry.getContext().unbindService(connection);
}
}
+
+ // connect to exposed provider
+ {
+ final String provider = "content://com.android.cts.normalapp.exposed.provider/table";
+ final Cursor testCursor = InstrumentationRegistry
+ .getContext().getContentResolver().query(
+ Uri.parse(provider),
+ null /*projection*/,
+ null /*selection*/,
+ null /*selectionArgs*/,
+ null /*sortOrder*/);
+ assertThat(testCursor, is(notNullValue()));
+ assertThat(testCursor.getCount(), is(1));
+ assertThat(testCursor.getColumnCount(), is(2));
+ assertThat(testCursor.moveToFirst(), is(true));
+ assertThat(testCursor.getInt(0), is(1));
+ assertThat(testCursor.getString(1), is("ExposedProvider"));
+ final TestResult testResult = getResult();
+ assertThat(testResult.getPackageName(),
+ is("com.android.cts.normalapp"));
+ assertThat(testResult.getComponentName(),
+ is("ExposedProvider"));
+ assertThat(testResult.getStatus(),
+ is("PASS"));
+ assertThat(testResult.getEphemeralPackageInfoExposed(),
+ is(true));
+ assertThat(testResult.getException(),
+ is(nullValue()));
+ }
}
@Test
@@ -607,6 +816,24 @@
InstrumentationRegistry.getContext().unbindService(connection);
}
}
+
+ // connect to the instant app provider
+ {
+ final String provider = "content://com.android.cts.ephemeralapp1.provider/table";
+ final Cursor testCursor = InstrumentationRegistry
+ .getContext().getContentResolver().query(
+ Uri.parse(provider),
+ null /*projection*/,
+ null /*selection*/,
+ null /*selectionArgs*/,
+ null /*sortOrder*/);
+ assertThat(testCursor, is(notNullValue()));
+ assertThat(testCursor.getCount(), is(1));
+ assertThat(testCursor.getColumnCount(), is(2));
+ assertThat(testCursor.moveToFirst(), is(true));
+ assertThat(testCursor.getInt(0), is(1));
+ assertThat(testCursor.getString(1), is("InstantAppProvider"));
+ }
}
@Test
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/EphemeralProvider.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/EphemeralProvider.java
new file mode 100644
index 0000000..d34d494
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/EphemeralProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.ephemeralapp1;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class EphemeralProvider extends ContentProvider {
+ private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ static {
+ sUriMatcher.addURI("com.android.cts.ephemeralapp1.provider", "table", 1);
+ }
+ private static final String[] sColumnNames = { "_ID", "name" };
+ private static final MatrixCursor sCursor = new MatrixCursor(sColumnNames, 1);
+ static {
+ sCursor.newRow().add(1).add("InstantAppProvider");
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return (sUriMatcher.match(uri) != 1) ? null : sCursor;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml
index 06d569e..78c282b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml
@@ -43,12 +43,23 @@
<action android:name="com.android.cts.ephemeraltest.START_EPHEMERAL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- </activity>
- <!-- This should still not be visible to other Instant Apps -->
- <activity
- android:name=".FakeExposedActivity"
+ </activity>
+
+ <!-- This should still not be visible to other Instant Apps -->
+ <activity
+ android:name=".ExposedActivity"
android:visibleToInstantApps="true"
android:theme="@android:style/Theme.NoDisplay" />
+
+ <!-- This should still not be visible to other Instant Apps -->
+ <provider
+ android:name=".EphemeralProvider"
+ android:authorities="com.android.cts.ephemeralapp2.provider"
+ android:exported="true">
+ <intent-filter android:priority="0">
+ <action android:name="com.android.cts.ephemeraltest.QUERY" />
+ </intent-filter>
+ </provider>
</application>
<instrumentation
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml
index ff542a4..4c27dba 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml
@@ -64,6 +64,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+
<service
android:name=".NormalService">
<!-- TEST: ephemeral apps can't see this service using query methods -->
@@ -91,6 +92,24 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
+
+ <provider
+ android:name=".NormalProvider"
+ android:authorities="com.android.cts.normalapp.provider"
+ android:exported="true">
+ <intent-filter android:priority="-20">
+ <action android:name="com.android.cts.ephemeraltest.QUERY" />
+ </intent-filter>
+ </provider>
+ <provider
+ android:name=".ExposedProvider"
+ android:authorities="com.android.cts.normalapp.exposed.provider"
+ android:visibleToInstantApps="true"
+ android:exported="true">
+ <intent-filter android:priority="-10">
+ <action android:name="com.android.cts.ephemeraltest.QUERY" />
+ </intent-filter>
+ </provider>
</application>
<instrumentation
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
index d428158..14ee824 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
@@ -17,6 +17,8 @@
package com.android.cts.normalapp;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@@ -27,6 +29,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ResolveInfo;
+import android.database.Cursor;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -83,9 +86,9 @@
@Test
public void testQuery() throws Exception {
- final Intent queryIntent = new Intent(ACTION_QUERY);
// query activities without flags
{
+ final Intent queryIntent = new Intent(ACTION_QUERY);
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
if (resolveInfo == null || resolveInfo.size() == 0) {
@@ -108,6 +111,7 @@
// query activities asking for ephemeral apps [we should only get normal apps]
{
+ final Intent queryIntent = new Intent(ACTION_QUERY);
final int MATCH_EPHEMERAL = 0x00800000;
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
@@ -130,8 +134,29 @@
is(false));
}
+ // query activities; directed package
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setPackage("com.android.cts.ephemeralapp1");
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+ assertThat(resolveInfo.size(), is(0));
+ }
+
+ // query activities; directed component
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setComponent(
+ new ComponentName("com.android.cts.ephemeralapp1",
+ "com.android.cts.ephemeralapp1.EphemeralActivity"));
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+ assertThat(resolveInfo.size(), is(0));
+ }
+
// query services without flags
{
+ final Intent queryIntent = new Intent(ACTION_QUERY);
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
if (resolveInfo == null || resolveInfo.size() == 0) {
@@ -154,6 +179,7 @@
// query services asking for ephemeral apps [we should only get normal apps]
{
+ final Intent queryIntent = new Intent(ACTION_QUERY);
final int MATCH_EPHEMERAL = 0x00800000;
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
@@ -175,6 +201,92 @@
assertThat(resolveInfo.get(1).instantAppAvailable,
is(false));
}
+
+ // query services; directed package
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setPackage("com.android.cts.ephemeralapp1");
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+ assertThat(resolveInfo.size(), is(0));
+ }
+
+ // query services; directed component
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setComponent(
+ new ComponentName("com.android.cts.ephemeralapp1",
+ "com.android.cts.ephemeralapp1.EphemeralService"));
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+ assertThat(resolveInfo.size(), is(0));
+ }
+
+ // query content providers without flags
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+ .getContext().getPackageManager().queryIntentContentProviders(
+ queryIntent, 0 /*flags*/);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(2));
+ assertThat(resolveInfo.get(0).providerInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(0).providerInfo.name,
+ is("com.android.cts.normalapp.ExposedProvider"));
+ assertThat(resolveInfo.get(1).providerInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(1).providerInfo.name,
+ is("com.android.cts.normalapp.NormalProvider"));
+ assertThat(resolveInfo.get(1).instantAppAvailable,
+ is(false));
+ }
+
+ // query content providers asking for ephemeral apps [we should only get normal apps]
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ final int MATCH_EPHEMERAL = 0x00800000;
+
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentContentProviders(
+ queryIntent, MATCH_EPHEMERAL);
+ if (resolveInfo == null || resolveInfo.size() == 0) {
+ fail("didn't resolve any intents");
+ }
+ assertThat(resolveInfo.size(), is(2));
+ assertThat(resolveInfo.get(0).providerInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(0).providerInfo.name,
+ is("com.android.cts.normalapp.ExposedProvider"));
+ assertThat(resolveInfo.get(1).providerInfo.packageName,
+ is("com.android.cts.normalapp"));
+ assertThat(resolveInfo.get(1).providerInfo.name,
+ is("com.android.cts.normalapp.NormalProvider"));
+ assertThat(resolveInfo.get(1).instantAppAvailable,
+ is(false));
+ }
+
+ // query content providers; directed package
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setPackage("com.android.cts.ephemeralapp1");
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentContentProviders(queryIntent, 0 /*flags*/);
+ assertThat(resolveInfo.size(), is(0));
+ }
+
+ // query content providers; directed component
+ {
+ final Intent queryIntent = new Intent(ACTION_QUERY);
+ queryIntent.setComponent(
+ new ComponentName("com.android.cts.ephemeralapp1",
+ "com.android.cts.ephemeralapp1.EphemeralProvider"));
+ final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+ .getPackageManager().queryIntentContentProviders(queryIntent, 0 /*flags*/);
+ assertThat(resolveInfo.size(), is(0));
+ }
}
@Test
@@ -220,6 +332,24 @@
assertThat(testResult.getException(),
is("android.content.pm.PackageManager$NameNotFoundException"));
}
+
+ // connect to the normal provider
+ {
+ final String provider = "content://com.android.cts.normalapp.provider/table";
+ final Cursor testCursor = InstrumentationRegistry
+ .getContext().getContentResolver().query(
+ Uri.parse(provider),
+ null /*projection*/,
+ null /*selection*/,
+ null /*selectionArgs*/,
+ null /*sortOrder*/);
+ assertThat(testCursor, is(notNullValue()));
+ assertThat(testCursor.getCount(), is(1));
+ assertThat(testCursor.getColumnCount(), is(2));
+ assertThat(testCursor.moveToFirst(), is(true));
+ assertThat(testCursor.getInt(0), is(1));
+ assertThat(testCursor.getString(1), is("NormalProvider"));
+ }
}
@Test
@@ -269,6 +399,19 @@
assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
assertThat("EphemeralActivity", is(testResult.getComponentName()));
}
+
+ // connect to the instant app provider
+ {
+ final String provider = "content://com.android.cts.ephemeralapp1.provider/table";
+ final Cursor testCursor = InstrumentationRegistry
+ .getContext().getContentResolver().query(
+ Uri.parse(provider),
+ null /*projection*/,
+ null /*selection*/,
+ null /*selectionArgs*/,
+ null /*sortOrder*/);
+ assertThat(testCursor, is(nullValue()));
+ }
}
private TestResult getResult() {
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ExposedProvider.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ExposedProvider.java
new file mode 100644
index 0000000..99658d4
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ExposedProvider.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 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.normalapp;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+import com.android.cts.util.TestResult;
+
+public class ExposedProvider extends ContentProvider {
+ private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ static {
+ sUriMatcher.addURI("com.android.cts.normalapp.exposed.provider", "table", 1);
+ }
+ private static final String[] sColumnNames = { "_ID", "name" };
+ private static final MatrixCursor sCursor = new MatrixCursor(sColumnNames, 1);
+ static {
+ sCursor.newRow().add(1).add("ExposedProvider");
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ boolean canAccessInstantApp = false;
+ String exception = null;
+ try {
+ canAccessInstantApp = tryAccessingInstantApp();
+ } catch (Throwable t) {
+ exception = t.getClass().getName();
+ }
+
+ TestResult.getBuilder()
+ .setPackageName("com.android.cts.normalapp")
+ .setComponentName("ExposedProvider")
+ .setStatus("PASS")
+ .setException(exception)
+ .setEphemeralPackageInfoExposed(canAccessInstantApp)
+ .build()
+ .broadcast(getContext());
+
+ return (sUriMatcher.match(uri) != 1) ? null : sCursor;
+ }
+
+ private boolean tryAccessingInstantApp() throws NameNotFoundException {
+ final PackageInfo info = getContext().getPackageManager()
+ .getPackageInfo("com.android.cts.ephemeralapp1", 0 /*flags*/);
+ return (info != null);
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/NormalProvider.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/NormalProvider.java
new file mode 100644
index 0000000..8351a27
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/NormalProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.normalapp;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class NormalProvider extends ContentProvider {
+ private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ static {
+ sUriMatcher.addURI("com.android.cts.normalapp.provider", "table", 1);
+ }
+ private static final String[] sColumnNames = { "_ID", "name" };
+ private static final MatrixCursor sCursor = new MatrixCursor(sColumnNames, 1);
+ static {
+ sCursor.newRow().add(1).add("NormalProvider");
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return (sUriMatcher.match(uri) != 1) ? null : sCursor;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index f5666d1..4b0bec3 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -103,6 +103,7 @@
* Verify we can write to our own package dirs.
*/
public void testAllPackageDirsWritable() throws Exception {
+ final long testValue = 12345000;
final List<File> paths = getAllPackageSpecificPaths(getContext());
for (File path : paths) {
assertNotNull("Valid media must be inserted during CTS", path);
@@ -122,6 +123,12 @@
assertEquals(32, readInt(directChild));
assertEquals(64, readInt(subdirChild));
+
+ assertTrue("Must be able to set last modified", directChild.setLastModified(testValue));
+ assertTrue("Must be able to set last modified", subdirChild.setLastModified(testValue));
+
+ assertEquals(testValue, directChild.lastModified());
+ assertEquals(testValue, subdirChild.lastModified());
}
for (File path : paths) {
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml
index 7a937d5..31f653d 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml
@@ -17,7 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.instant.cookie"
android:versionCode="1"
- android:versionName="1.0">
+ android:versionName="1.0"
+ android:targetSandboxVersion="2">
<application/>
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 22eaaea..9778f12 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -41,6 +41,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.UUID;
/**
* Client app for verifying storage behaviors.
@@ -85,8 +86,10 @@
public void testVerifySpaceApi() throws Exception {
final StorageManager sm = getContext().getSystemService(StorageManager.class);
- final long cacheSize = sm.getCacheSizeBytes(getContext().getCacheDir());
- final long extCacheSize = sm.getCacheSizeBytes(getContext().getExternalCacheDir());
+ final long cacheSize = sm.getCacheSizeBytes(
+ sm.getUuidForPath(getContext().getCacheDir()));
+ final long extCacheSize = sm.getCacheSizeBytes(
+ sm.getUuidForPath(getContext().getExternalCacheDir()));
if (cacheSize == extCacheSize) {
assertMostlyEquals(CACHE_ALL, cacheSize);
} else {
@@ -97,22 +100,28 @@
public void testVerifyQuotaApi() throws Exception {
final StorageManager sm = getContext().getSystemService(StorageManager.class);
- assertTrue("Apps must have at least 10MB quota",
- sm.getCacheQuotaBytes(getContext().getCacheDir()) > 10 * MB_IN_BYTES);
+
+ final long cacheSize = sm.getCacheQuotaBytes(
+ sm.getUuidForPath(getContext().getCacheDir()));
+ assertTrue("Apps must have at least 10MB quota", cacheSize > 10 * MB_IN_BYTES);
}
public void testVerifyAllocateApi() throws Exception {
final StorageManager sm = getContext().getSystemService(StorageManager.class);
final File filesDir = getContext().getFilesDir();
- assertTrue("Apps must be able to allocate internal space",
- sm.getAllocatableBytes(filesDir, 0) > 10 * MB_IN_BYTES);
final File extDir = Environment.getExternalStorageDirectory();
+
+ final UUID filesUuid = sm.getUuidForPath(filesDir);
+ final UUID extUuid = sm.getUuidForPath(extDir);
+
+ assertTrue("Apps must be able to allocate internal space",
+ sm.getAllocatableBytes(filesUuid, 0) > 10 * MB_IN_BYTES);
assertTrue("Apps must be able to allocate external space",
- sm.getAllocatableBytes(extDir, 0) > 10 * MB_IN_BYTES);
+ sm.getAllocatableBytes(extUuid, 0) > 10 * MB_IN_BYTES);
// Should always be able to allocate 1MB indirectly
- sm.allocateBytes(filesDir, 1 * MB_IN_BYTES, 0);
+ sm.allocateBytes(filesUuid, 1 * MB_IN_BYTES, 0);
// Should always be able to allocate 1MB directly
final File filesFile = makeUniqueFile(filesDir);
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
index 64495a4..e47f6ed 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
@@ -25,10 +25,12 @@
import junit.framework.AssertionFailedError;
+import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -152,7 +154,21 @@
return success;
}
- public static boolean shouldHaveQuota(StructUtsname uname) {
+ public static boolean shouldHaveQuota(StructUtsname uname) throws Exception {
+ try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ final String[] fields = line.split(" ");
+ final String target = fields[1];
+ final String format = fields[2];
+
+ if (target.equals("/data") && !format.equals("ext4")) {
+ Log.d(TAG, "Assuming no quota support because /data is " + format);
+ return false;
+ }
+ }
+ }
+
final Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)").matcher(uname.release);
if (!matcher.find()) {
throw new IllegalStateException("Failed to parse version: " + uname.release);
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java
index bab84aa..2845185 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java
@@ -50,13 +50,13 @@
public static Bundle doAllocation(Context context, Bundle extras) {
final StorageManager sm = context.getSystemService(StorageManager.class);
- final double fraction = extras.getDouble(EXTRA_FRACTION, 0);
- final long quota = sm.getCacheQuotaBytes(context.getCacheDir());
- final long bytes = (long) (quota * fraction);
- final long time = extras.getLong(EXTRA_TIME, System.currentTimeMillis());
-
long allocated = 0;
try {
+ final double fraction = extras.getDouble(EXTRA_FRACTION, 0);
+ final long quota = sm.getCacheQuotaBytes(sm.getUuidForPath(context.getCacheDir()));
+ final long bytes = (long) (quota * fraction);
+ final long time = extras.getLong(EXTRA_TIME, System.currentTimeMillis());
+
while (allocated < bytes) {
final File f = makeUniqueFile(context.getCacheDir());
final long size = 1024 * 1024;
@@ -64,15 +64,15 @@
f.setLastModified(time);
allocated += Os.stat(f.getAbsolutePath()).st_blocks * 512;
}
+
+ Log.d(TAG, "Quota " + quota + ", target " + bytes + ", allocated " + allocated);
+
+ final Bundle res = new Bundle();
+ res.putLong(EXTRA_BYTES, allocated);
+ return res;
} catch (Exception e) {
Log.e(TAG, "Failed to allocate cache files", e);
return null;
}
-
- Log.d(TAG, "Quota " + quota + ", target " + bytes + ", allocated " + allocated);
-
- final Bundle res = new Bundle();
- res.putLong(EXTRA_BYTES, allocated);
- return res;
}
}
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
index 8066f70..41439f0 100644
--- a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
@@ -16,6 +16,8 @@
package com.android.cts.storagestatsapp;
+import static android.os.storage.StorageManager.UUID_DEFAULT;
+
import static com.android.cts.storageapp.Utils.CACHE_ALL;
import static com.android.cts.storageapp.Utils.DATA_ALL;
import static com.android.cts.storageapp.Utils.MB_IN_BYTES;
@@ -54,6 +56,7 @@
import com.android.cts.storageapp.UtilsReceiver;
import java.io.File;
+import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -81,15 +84,18 @@
.getSystemService(StorageStatsManager.class);
assertTrue("You're running kernel 3.18 or newer (" + uname.release + ") which "
+ "means that CONFIG_QUOTA, CONFIG_QFMT_V2, CONFIG_QUOTACTL and the "
- + "'quota' fstab option on /data are required", stats.isQuotaSupported(null));
+ + "'quota' fstab option on /data are required",
+ stats.isQuotaSupported(UUID_DEFAULT));
}
}
public void testVerifySummary() throws Exception {
final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
- assertAtLeast(Environment.getDataDirectory().getTotalSpace(), stats.getTotalBytes(null));
- assertAtLeast(Environment.getDataDirectory().getUsableSpace(), stats.getFreeBytes(null));
+ assertAtLeast(Environment.getDataDirectory().getTotalSpace(),
+ stats.getTotalBytes(UUID_DEFAULT));
+ assertAtLeast(Environment.getDataDirectory().getUsableSpace(),
+ stats.getFreeBytes(UUID_DEFAULT));
}
public void testVerifyStats() throws Exception {
@@ -97,13 +103,13 @@
final int uid = android.os.Process.myUid();
final UserHandle user = UserHandle.getUserHandleForUid(uid);
- final StorageStats beforeApp = stats.queryStatsForUid(null, uid);
- final StorageStats beforeUser = stats.queryStatsForUser(null, user);
+ final StorageStats beforeApp = stats.queryStatsForUid(UUID_DEFAULT, uid);
+ final StorageStats beforeUser = stats.queryStatsForUser(UUID_DEFAULT, user);
useSpace(getContext());
- final StorageStats afterApp = stats.queryStatsForUid(null, uid);
- final StorageStats afterUser = stats.queryStatsForUser(null, user);
+ final StorageStats afterApp = stats.queryStatsForUid(UUID_DEFAULT, uid);
+ final StorageStats afterUser = stats.queryStatsForUser(UUID_DEFAULT, user);
final long deltaData = DATA_ALL;
assertMostlyEquals(deltaData, afterApp.getDataBytes() - beforeApp.getDataBytes());
@@ -121,8 +127,8 @@
final ApplicationInfo a = pm.getApplicationInfo(PKG_A, 0);
final ApplicationInfo b = pm.getApplicationInfo(PKG_B, 0);
- final StorageStats as = stats.queryStatsForUid(null, a.uid);
- final StorageStats bs = stats.queryStatsForUid(null, b.uid);
+ final StorageStats as = stats.queryStatsForUid(UUID_DEFAULT, a.uid);
+ final StorageStats bs = stats.queryStatsForUid(UUID_DEFAULT, b.uid);
assertMostlyEquals(DATA_ALL * 2, as.getDataBytes());
assertMostlyEquals(CACHE_ALL * 2, as.getCacheBytes());
@@ -140,7 +146,7 @@
final int uid = android.os.Process.myUid();
final UserHandle user = UserHandle.getUserHandleForUid(uid);
- final ExternalStorageStats before = stats.queryExternalStatsForUser(null, user);
+ final ExternalStorageStats before = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
final File dir = Environment.getExternalStorageDirectory();
final File downloadsDir = Environment.getExternalStoragePublicDirectory(
@@ -158,7 +164,7 @@
useWrite(audio, 5 * MB_IN_BYTES);
useWrite(internal, 7 * MB_IN_BYTES);
- final ExternalStorageStats afterInit = stats.queryExternalStatsForUser(null, user);
+ final ExternalStorageStats afterInit = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
assertMostlyEquals(17 * MB_IN_BYTES, afterInit.getTotalBytes() - before.getTotalBytes());
assertMostlyEquals(5 * MB_IN_BYTES, afterInit.getAudioBytes() - before.getAudioBytes());
@@ -168,7 +174,7 @@
// Rename to ensure that stats are updated
video.renameTo(new File(dir, System.nanoTime() + ".PnG"));
- final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(null, user);
+ final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
assertMostlyEquals(17 * MB_IN_BYTES, afterRename.getTotalBytes() - before.getTotalBytes());
assertMostlyEquals(5 * MB_IN_BYTES, afterRename.getAudioBytes() - before.getAudioBytes());
@@ -199,9 +205,9 @@
logCommand("sync");
final long manualSize = getSizeManual(Environment.getExternalStorageDirectory());
- final long statsSize = stats.queryExternalStatsForUser(null, user).getTotalBytes();
+ final long statsSize = stats.queryExternalStatsForUser(UUID_DEFAULT, user).getTotalBytes();
- assertEquals(manualSize, statsSize);
+ assertMostlyEquals(manualSize, statsSize);
}
public void testVerifyCategory() throws Exception {
@@ -220,9 +226,10 @@
final UserHandle user = android.os.Process.myUserHandle();
final File filesDir = context.getFilesDir();
+ final UUID filesUuid = sm.getUuidForPath(filesDir);
- final long beforeAllocatable = sm.getAllocatableBytes(filesDir, 0);
- final long beforeFree = stats.getFreeBytes(null);
+ final long beforeAllocatable = sm.getAllocatableBytes(filesUuid, 0);
+ final long beforeFree = stats.getFreeBytes(UUID_DEFAULT);
final long beforeRaw = filesDir.getUsableSpace();
Log.d(TAG, "Before raw " + beforeRaw + ", free " + beforeFree + ", allocatable "
@@ -234,16 +241,24 @@
// Ask apps to allocate some cached data
final long targetA = doAllocateProvider(PKG_A, 0.5, 1262304000);
final long targetB = doAllocateProvider(PKG_B, 2.0, 1420070400);
+ final long totalAllocated = targetA + targetB;
// Apps using up some cache space shouldn't change how much we can
// allocate, or how much we think is free; but it should decrease real
// disk space.
- assertMostlyEquals(beforeAllocatable, sm.getAllocatableBytes(filesDir, 0),
- 10 * MB_IN_BYTES);
- assertMostlyEquals(beforeFree, stats.getFreeBytes(null),
- 10 * MB_IN_BYTES);
- assertMostlyEquals(targetA + targetB, beforeRaw - filesDir.getUsableSpace(),
- 10 * MB_IN_BYTES);
+ if (stats.isQuotaSupported(UUID_DEFAULT)) {
+ assertMostlyEquals(beforeAllocatable,
+ sm.getAllocatableBytes(filesUuid, 0), 10 * MB_IN_BYTES);
+ assertMostlyEquals(beforeFree,
+ stats.getFreeBytes(UUID_DEFAULT), 10 * MB_IN_BYTES);
+ } else {
+ assertMostlyEquals(beforeAllocatable - totalAllocated,
+ sm.getAllocatableBytes(filesUuid, 0), 10 * MB_IN_BYTES);
+ assertMostlyEquals(beforeFree - totalAllocated,
+ stats.getFreeBytes(UUID_DEFAULT), 10 * MB_IN_BYTES);
+ }
+ assertMostlyEquals(beforeRaw - totalAllocated,
+ filesDir.getUsableSpace(), 10 * MB_IN_BYTES);
assertMostlyEquals(targetA, getCacheBytes(PKG_A, user));
assertMostlyEquals(targetB, getCacheBytes(PKG_B, user));
@@ -251,7 +266,7 @@
// Allocate some space for ourselves, which should trim away at
// over-quota app first, even though its files are newer.
final long clear1 = filesDir.getUsableSpace() + (targetB / 2);
- sm.allocateBytes(filesDir, clear1, 0);
+ sm.allocateBytes(filesUuid, clear1, 0);
assertMostlyEquals(targetA, getCacheBytes(PKG_A, user));
assertMostlyEquals(targetB / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES);
@@ -261,7 +276,7 @@
// they're tied for cache ratios, we expect to clear about half of the
// remaining space from each of them.
final long clear2 = filesDir.getUsableSpace() + (targetB / 2);
- sm.allocateBytes(filesDir, clear2, 0);
+ sm.allocateBytes(filesUuid, clear2, 0);
assertMostlyEquals(targetA / 2, getCacheBytes(PKG_A, user), 2 * MB_IN_BYTES);
assertMostlyEquals(targetA / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES);
@@ -305,7 +320,7 @@
tomb.setLastModified(tombTime);
final long clear1 = group.getUsableSpace() + (8 * MB_IN_BYTES);
- sm.allocateBytes(group, clear1, 0);
+ sm.allocateBytes(sm.getUuidForPath(group), clear1, 0);
assertTrue(a.exists());
assertTrue(b.exists());
@@ -319,9 +334,9 @@
assertTrue(i.exists()); assertEquals(0, i.length());
}
- private long getCacheBytes(String pkg, UserHandle user) {
+ private long getCacheBytes(String pkg, UserHandle user) throws Exception {
return getContext().getSystemService(StorageStatsManager.class)
- .queryStatsForPackage(null, pkg, user).getCacheBytes();
+ .queryStatsForPackage(UUID_DEFAULT, pkg, user).getCacheBytes();
}
private long doAllocateReceiver(String pkg, double fraction, long time) throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index f8f6d92..4340c87 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -267,6 +267,11 @@
getUiDevice().pressBack();
waitForIdle();
+ if (isTv()) {
+ getUiDevice().pressHome();
+ waitForIdle();
+ }
+
// Open the app details settings
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
@@ -506,4 +511,9 @@
getInstrumentation().getUiAutomation().waitForIdle(IDLE_TIMEOUT_MILLIS,
GLOBAL_TIMEOUT_MILLIS);
}
+
+ private static boolean isTv() {
+ return getInstrumentation().getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
index c7b8f8b..0a1f012 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -34,6 +34,17 @@
public class UsesLibraryTest extends InstrumentationTestCase {
private static final String TAG = "UsesLibraryTest";
+ public void testUsesLibrary() throws Exception {
+ ClassLoader loader = getClass().getClassLoader();
+ if (loader instanceof BaseDexClassLoader) {
+ Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
+ for (Object dexElement : dexElements) {
+ DexFile dexFile = getDexFileFromDexElement(dexElement);
+ assertTrue(isDexFileBackedByOatFile(dexFile));
+ }
+ }
+ }
+
public void testMissingLibrary() throws Exception {
ClassLoader loader = getClass().getClassLoader();
if (loader instanceof BaseDexClassLoader) {
diff --git a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
index 40bf530..ce8f760 100644
--- a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
@@ -75,8 +75,7 @@
private byte[] profileBytes;
private File localProfileFile;
private File apkFile;
- private boolean mIsRoot;
- private boolean mNewlyObtainedRoot;
+ private boolean mCanEnableDeviceRootAccess;
@Override
protected void setUp() throws Exception {
@@ -87,11 +86,8 @@
assertTrue("Unknown build type: " + buildType,
Arrays.asList("user", "userdebug", "eng").contains(buildType));
boolean wasRoot = mDevice.isAdbRoot();
- mIsRoot = (!buildType.equals("user"));
- mNewlyObtainedRoot = (mIsRoot && !wasRoot);
- if (mNewlyObtainedRoot) {
- mDevice.enableAdbRoot();
- }
+ // We can only enable root access on userdebug and eng builds.
+ mCanEnableDeviceRootAccess = buildType.equals("userdebug") || buildType.equals("eng");
apkFile = File.createTempFile("CtsCompilationApp", ".apk");
try (OutputStream outputStream = new FileOutputStream(apkFile)) {
@@ -111,9 +107,6 @@
@Override
protected void tearDown() throws Exception {
- if (mNewlyObtainedRoot) {
- mDevice.disableAdbRoot();
- }
FileUtil.deleteFile(apkFile);
FileUtil.deleteFile(localProfileFile);
mDevice.uninstallPackage(APPLICATION_PACKAGE);
@@ -165,7 +158,7 @@
EnumSet.of(ProfileLocation.CUR));
if (didRun) {
assertTrue("ref profile should have been created by the compiler",
- mDevice.doesFileExist(ProfileLocation.REF.getPath()));
+ doesFileExist(ProfileLocation.REF.getPath()));
}
}
@@ -184,10 +177,10 @@
private byte[] readFileOnClient(String clientPath) throws Exception {
assertTrue("File not found on client: " + clientPath,
- mDevice.doesFileExist(clientPath));
+ doesFileExist(clientPath));
File copyOnHost = File.createTempFile("host", "copy");
try {
- executeAdbCommand("pull", clientPath, copyOnHost.getPath());
+ executePull(clientPath, copyOnHost.getPath());
return Files.toByteArray(copyOnHost);
} finally {
FileUtil.deleteFile(copyOnHost);
@@ -209,8 +202,8 @@
// ensure no profiles initially present
for (ProfileLocation profileLocation : ProfileLocation.values()) {
String clientPath = profileLocation.getPath();
- if (mDevice.doesFileExist(clientPath)) {
- executeAdbCommand(0, "shell", "rm", clientPath);
+ if (doesFileExist(clientPath)) {
+ executeSuShellAdbCommand(0, "rm", clientPath);
}
}
executeCompile("-m", "speed-profile", "-f");
@@ -247,11 +240,11 @@
* @param compileOptions extra options to pass to the compiler on the command line
*/
private void executeCompile(String... compileOptions) throws Exception {
- List<String> command = new ArrayList<>(Arrays.asList("shell", "cmd", "package", "compile"));
+ List<String> command = new ArrayList<>(Arrays.asList("cmd", "package", "compile"));
command.addAll(Arrays.asList(compileOptions));
command.add(APPLICATION_PACKAGE);
String[] commandArray = command.toArray(new String[0]);
- assertEquals("Success", executeAdbCommand(1, commandArray)[0]);
+ assertEquals("Success", executeSuShellAdbCommand(1, commandArray)[0]);
}
/**
@@ -261,21 +254,21 @@
String targetPath = location.getPath();
// Get the owner of the parent directory so we can set it on the file
String targetDir = location.getDirectory();
- if (!mDevice.doesFileExist(targetDir)) {
+ if (!doesFileExist(targetDir)) {
fail("Not found: " + targetPath);
}
// in format group:user so we can directly pass it to chown
- String owner = executeAdbCommand(1, "shell", "stat", "-c", "%U:%g", targetDir)[0];
+ String owner = executeSuShellAdbCommand(1, "stat", "-c", "%U:%g", targetDir)[0];
// for some reason, I've observed the output starting with a single space
while (owner.startsWith(" ")) {
owner = owner.substring(1);
}
- mDevice.executeAdbCommand("push", localProfileFile.getAbsolutePath(), targetPath);
- executeAdbCommand(0, "shell", "chown", owner, targetPath);
+ executePush(localProfileFile.getAbsolutePath(), targetPath);
+ executeSuShellAdbCommand(0, "chown", owner, targetPath);
// Verify that the file was written successfully
- assertTrue("failed to create profile file", mDevice.doesFileExist(targetPath));
+ assertTrue("failed to create profile file", doesFileExist(targetPath));
assertEquals(Integer.toString(profileBytes.length),
- executeAdbCommand(1, "shell", "stat", "-c", "%s", targetPath)[0]);
+ executeSuShellAdbCommand(1, "stat", "-c", "%s", targetPath)[0]);
}
/**
@@ -283,8 +276,8 @@
* {@code oatdump --header-only}.
*/
private String getCompilerFilter(String odexFilePath) throws DeviceNotAvailableException {
- String[] response = executeAdbCommand(
- "shell", "oatdump", "--header-only", "--oat-file=" + odexFilePath);
+ String[] response = executeSuShellAdbCommand(
+ "oatdump", "--header-only", "--oat-file=" + odexFilePath);
String prefix = "compiler-filter =";
for (String line : response) {
line = line.trim();
@@ -302,14 +295,14 @@
*/
private String getOdexFilePath() throws DeviceNotAvailableException {
// Something like "package:/data/app/android.cts.compilation-1/base.apk"
- String pathSpec = executeAdbCommand(1, "shell", "pm", "path", APPLICATION_PACKAGE)[0];
+ String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
Matcher matcher = Pattern.compile("^package:(.+/)base\\.apk$").matcher(pathSpec);
boolean found = matcher.find();
assertTrue("Malformed spec: " + pathSpec, found);
String apkDir = matcher.group(1);
// E.g. /data/app/android.cts.compilation-1/oat/arm64/base.odex
- String result = executeAdbCommand(1, "shell", "find", apkDir, "-name", "base.odex")[0];
- assertTrue("odex file not found: " + result, mDevice.doesFileExist(result));
+ String result = executeSuShellAdbCommand(1, "find", apkDir, "-name", "base.odex")[0];
+ assertTrue("odex file not found: " + result, doesFileExist(result));
return result;
}
@@ -323,23 +316,24 @@
* TODO: Use Assume.assumeTrue() if this test gets converted to JUnit 4.
*/
private boolean canRunTest(Set<ProfileLocation> profileLocations) throws Exception {
- boolean result = mIsRoot && (profileLocations.isEmpty() || isUseJitProfiles());
+ boolean result = mCanEnableDeviceRootAccess &&
+ (profileLocations.isEmpty() || isUseJitProfiles());
if (!result) {
- System.err.printf("Skipping test [isRoot=%s, %d profiles] on %s\n",
- mIsRoot, profileLocations.size(), mDevice);
+ System.err.printf("Skipping test [mCanEnableDeviceRootAccess=%s, %d profiles] on %s\n",
+ mCanEnableDeviceRootAccess, profileLocations.size(), mDevice);
}
return result;
}
private boolean isUseJitProfiles() throws Exception {
boolean propUseJitProfiles = Boolean.parseBoolean(
- executeAdbCommand(1, "shell", "getprop", "dalvik.vm.usejitprofiles")[0]);
+ executeSuShellAdbCommand(1, "getprop", "dalvik.vm.usejitprofiles")[0]);
return propUseJitProfiles;
}
- private String[] executeAdbCommand(int numLinesOutputExpected, String... command)
+ private String[] executeSuShellAdbCommand(int numLinesOutputExpected, String... command)
throws DeviceNotAvailableException {
- String[] lines = executeAdbCommand(command);
+ String[] lines = executeSuShellAdbCommand(command);
assertEquals(
String.format(Locale.US, "Expected %d lines output, got %d running %s: %s",
numLinesOutputExpected, lines.length, Arrays.toString(command),
@@ -348,10 +342,38 @@
return lines;
}
- private String[] executeAdbCommand(String... command) throws DeviceNotAvailableException {
- String output = mDevice.executeAdbCommand(command);
+ private String[] executeSuShellAdbCommand(String... command)
+ throws DeviceNotAvailableException {
+ // Add `shell su root` to the adb command.
+ String cmdString = String.join(" ", command);
+ String output = mDevice.executeShellCommand("su root " + cmdString);
// "".split() returns { "" }, but we want an empty array
String[] lines = output.equals("") ? new String[0] : output.split("\n");
return lines;
}
+
+ private void executePush(String hostPath, String targetPath)
+ throws DeviceNotAvailableException {
+ String tmpPath = "/data/local/tmp/" + APPLICATION_PACKAGE + ".push.tmp";
+ assertTrue(mDevice.pushFile(new File(hostPath), tmpPath));
+ executeSuShellAdbCommand("mv", tmpPath, targetPath);
+ }
+
+ private void executePull(String targetPath, String hostPath)
+ throws DeviceNotAvailableException {
+ String tmpPath = "/data/local/tmp/" + APPLICATION_PACKAGE + ".pull.tmp";
+ executeSuShellAdbCommand("cp", targetPath, tmpPath);
+ try {
+ executeSuShellAdbCommand("chmod", "606", tmpPath);
+ assertTrue(mDevice.pullFile(tmpPath, new File(hostPath)));
+ } finally {
+ executeSuShellAdbCommand("rm", tmpPath);
+ }
+ }
+
+ private boolean doesFileExist(String path) throws DeviceNotAvailableException {
+ String[] result = executeSuShellAdbCommand("ls", path);
+ // Testing for empty directories will return an empty array.
+ return !(result.length > 0 && result[0].contains("No such file"));
+ }
}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.xml b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.xml
index cee1a50..398a75b 100644
--- a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.xml
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.content">
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+
<application>
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
index fe4414b..2b08e1f5 100644
--- a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
@@ -25,7 +25,10 @@
import android.content.Intent;
import android.content.SyncRequest;
import android.content.SyncResult;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.Bundle;
+import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
@@ -45,13 +48,17 @@
*/
@RunWith(AndroidJUnit4.class)
public class CtsSyncAccountAccessOtherCertTestCases {
- private static final long SYNC_TIMEOUT_MILLIS = 10000; // 20 sec
+ private static final long SYNC_TIMEOUT_MILLIS = 10000; // 10 sec
private static final long UI_TIMEOUT_MILLIS = 5000; // 5 sec
public static final String TOKEN_TYPE_REMOVE_ACCOUNTS = "TOKEN_TYPE_REMOVE_ACCOUNTS";
@Test
public void testAccountAccess_otherCertAsAuthenticatorCanNotSeeAccount() throws Exception {
+ if (!hasDataConnection()) {
+ return;
+ }
+
Intent intent = new Intent(getContext(), StubActivity.class);
Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
@@ -63,6 +70,8 @@
result.getString(AccountManager.KEY_ACCOUNT_NAME),
result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ waitForSyncManagerAccountChangeUpdate();
+
try {
CountDownLatch latch = new CountDownLatch(1);
@@ -114,4 +123,17 @@
private UiDevice getUiDevice() {
return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
}
+
+ private void waitForSyncManagerAccountChangeUpdate() {
+ // Wait for the sync manager to be notified for the new account.
+ // Unfortunately, there is no way to detect this event, sigh...
+ SystemClock.sleep(5000);
+ }
+
+ private boolean hasDataConnection() {
+ ConnectivityManager connectivityManager = getContext().getSystemService(
+ ConnectivityManager.class);
+ NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
+ return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
+ }
}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.xml b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.xml
index ea46d61..2ecd27d 100644
--- a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.xml
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.content">
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+
<application>
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java
index 17be8b6..223281b 100644
--- a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java
@@ -27,7 +27,10 @@
import android.content.Intent;
import android.content.SyncRequest;
import android.content.SyncResult;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.Bundle;
+import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
@@ -41,10 +44,14 @@
*/
@RunWith(AndroidJUnit4.class)
public class CtsSyncAccountAccessSameCertTestCases {
- private static final long SYNC_TIMEOUT_MILLIS = 10000; // 20 sec
+ private static final long SYNC_TIMEOUT_MILLIS = 10000; // 10 sec
@Test
public void testAccountAccess_sameCertAsAuthenticatorCanSeeAccount() throws Exception {
+ if (!hasDataConnection()) {
+ return;
+ }
+
Intent intent = new Intent(getContext(), StubActivity.class);
Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
@@ -56,6 +63,8 @@
result.getString(AccountManager.KEY_ACCOUNT_NAME),
result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ waitForSyncManagerAccountChangeUpdate();
+
try {
CountDownLatch latch = new CountDownLatch(1);
@@ -85,4 +94,17 @@
private Context getContext() {
return InstrumentationRegistry.getInstrumentation().getContext();
}
+
+ private void waitForSyncManagerAccountChangeUpdate() {
+ // Wait for the sync manager to be notified for the new account.
+ // Unfortunately, there is no way to detect this event, sigh...
+ SystemClock.sleep(5000);
+ }
+
+ private boolean hasDataConnection() {
+ ConnectivityManager connectivityManager = getContext().getSystemService(
+ ConnectivityManager.class);
+ NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
+ return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
+ }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAdmin/src/com.android.cts.deviceadmin/DeviceOwnerPasswordTest.java b/hostsidetests/devicepolicy/app/DeviceAdmin/src/com.android.cts.deviceadmin/DeviceOwnerPasswordTest.java
index d7c3bcf..6a01ea6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdmin/src/com.android.cts.deviceadmin/DeviceOwnerPasswordTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAdmin/src/com.android.cts.deviceadmin/DeviceOwnerPasswordTest.java
@@ -46,7 +46,7 @@
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
dpm.getPasswordQuality(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(false);
String caseDescription = "initial";
assertPasswordSucceeds("1234", caseDescription);
@@ -56,7 +56,7 @@
dpm.setPasswordMinimumLength(mAdminComponent, 10);
caseDescription = "minimum password length = 10";
assertEquals(10, dpm.getPasswordMinimumLength(mAdminComponent));
- assertTrue(dpm.isActivePasswordSufficient()); // length not checked for this quality
+ assertPasswordSufficiency(true); // length not checked for this quality
// TODO(ascull): fix resetPassword() logic so these succeed
assertPasswordFails("1234", caseDescription);
@@ -67,7 +67,7 @@
caseDescription = "minimum password length = 4";
assertEquals(4, dpm.getPasswordMinimumLength(
mAdminComponent));
- assertTrue(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(true);
assertPasswordSucceeds("1234", caseDescription);
assertPasswordSucceeds("abcd", caseDescription);
@@ -79,7 +79,7 @@
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
dpm.getPasswordQuality(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient()); // failure
+ assertPasswordSufficiency(false); // failure
String caseDescription = "initial";
assertPasswordSucceeds("1234", caseDescription);
@@ -89,7 +89,7 @@
dpm.setPasswordMinimumLength(mAdminComponent, 10);
caseDescription = "minimum password length = 10";
assertEquals(10, dpm.getPasswordMinimumLength(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(false);
assertPasswordFails("1234", caseDescription);
assertPasswordFails("abcd", caseDescription);
@@ -99,7 +99,7 @@
caseDescription = "minimum password length = 4";
assertEquals(4, dpm.getPasswordMinimumLength(
mAdminComponent));
- assertTrue(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(true);
assertPasswordSucceeds("1234", caseDescription);
assertPasswordSucceeds("abcd", caseDescription);
@@ -111,7 +111,7 @@
DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
dpm.getPasswordQuality(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(false);
String caseDescription = "initial";
assertPasswordFails("1234", caseDescription); // can't change
@@ -121,7 +121,7 @@
dpm.setPasswordMinimumLength(mAdminComponent, 10);
caseDescription = "minimum password length = 10";
assertEquals(10, dpm.getPasswordMinimumLength(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(false);
assertPasswordFails("1234", caseDescription);
assertPasswordFails("abcd", caseDescription);
@@ -131,7 +131,7 @@
caseDescription = "minimum password length = 4";
assertEquals(4, dpm.getPasswordMinimumLength(
mAdminComponent));
- assertTrue(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(true);
assertPasswordFails("1234", caseDescription);
assertPasswordSucceeds("abcd", caseDescription);
@@ -143,7 +143,7 @@
DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
dpm.getPasswordQuality(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(false);
String caseDescription = "initial";
assertPasswordFails("1234", caseDescription);
@@ -153,7 +153,7 @@
dpm.setPasswordMinimumLength(mAdminComponent, 10);
caseDescription = "minimum password length = 10";
assertEquals(10, dpm.getPasswordMinimumLength(mAdminComponent));
- assertFalse(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(false);
assertPasswordFails("1234", caseDescription);
assertPasswordFails("abcd", caseDescription);
@@ -163,7 +163,7 @@
caseDescription = "minimum password length = 4";
assertEquals(4, dpm.getPasswordMinimumLength(
mAdminComponent));
- assertTrue(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(true);
assertPasswordFails("1234", caseDescription);
assertPasswordFails("abcd", caseDescription);
@@ -372,6 +372,21 @@
private void assertPasswordSucceeds(String password, String restriction) {
boolean passwordResetResult = dpm.resetPassword(password, /* flags= */0);
assertTrue("Password '" + password + "' failed on " + restriction, passwordResetResult);
- assertTrue(dpm.isActivePasswordSufficient());
+ assertPasswordSufficiency(true);
+ }
+
+ private void assertPasswordSufficiency(boolean expectPasswordSufficient) {
+ int retries = 15;
+ // isActivePasswordSufficient() gets the result asynchronously so let's retry a few times
+ while (retries >= 0 && dpm.isActivePasswordSufficient() != expectPasswordSufficient) {
+ retries--;
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ assertEquals(expectPasswordSufficient, dpm.isActivePasswordSufficient());
+
}
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
index 302f9da..c9cf648 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
@@ -44,6 +44,7 @@
private static final String DELEGATE_PKG = "com.android.cts.delegate";
private static final String DELEGATE_ACTIVITY_NAME =
DELEGATE_PKG + ".DelegatedScopesReceiverActivity";
+ private static final String TEST_PKG = "com.android.cts.apprestrictions.targetapp";
// Broadcasts received from the delegate app.
private static final String ACTION_REPORT_SCOPES = "com.android.cts.delegate.report_scopes";
@@ -130,6 +131,53 @@
.getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, NON_EXISTENT_PKG).isEmpty());
}
+ public void testCanRetrieveDelegates() {
+ final List<String> someScopes = Arrays.asList(
+ DELEGATION_APP_RESTRICTIONS,
+ DELEGATION_ENABLE_SYSTEM_APP);
+ final List<String> otherScopes = Arrays.asList(
+ DELEGATION_BLOCK_UNINSTALL,
+ DELEGATION_ENABLE_SYSTEM_APP);
+
+ // In the beginning there are no delegates.
+ assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
+ .isEmpty());
+ assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
+ .isEmpty());
+ assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
+ .isEmpty());
+
+ // After delegating scopes to two packages.
+ mDevicePolicyManager.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT,
+ DELEGATE_PKG, someScopes);
+ mDevicePolicyManager.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT,
+ TEST_PKG, otherScopes);
+
+ // The expected delegates are returned.
+ assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
+ .contains(DELEGATE_PKG));
+ assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
+ .contains(TEST_PKG));
+ assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
+ .contains(DELEGATE_PKG));
+ assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
+ .contains(TEST_PKG));
+
+ // Packages are only returned in their recpective scopes.
+ assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
+ .contains(TEST_PKG));
+ assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
+ .contains(DELEGATE_PKG));
+ assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
+ .contains(DELEGATE_PKG));
+ assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
+ .contains(TEST_PKG));
+ }
+
+ private List<String> getDelegatePackages(String scope) {
+ return mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT, scope);
+ }
+
private void startAndWaitDelegateActivity() throws InterruptedException {
mContext.startActivity(new Intent()
.setComponent(new ComponentName(DELEGATE_PKG, DELEGATE_ACTIVITY_NAME))
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
index ff51e9e..0694d76 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
@@ -16,7 +16,6 @@
package com.android.cts.deviceowner;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Process;
@@ -25,7 +24,6 @@
import com.android.org.conscrypt.TrustedCertificateStore;
import java.io.ByteArrayInputStream;
-import java.lang.reflect.Method;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.List;
@@ -133,9 +131,7 @@
mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), true);
long timeBefore = System.currentTimeMillis();
- final Method retrieveNetworkLogsMethod = DevicePolicyManager.class.getDeclaredMethod(
- "retrieveNetworkLogs", ComponentName.class, long.class);
- retrieveNetworkLogsMethod.invoke(mDevicePolicyManager, getWho(), 0 /* batchToken */);
+ mDevicePolicyManager.retrieveNetworkLogs(getWho(), 0 /* batchToken */);
long timeAfter = System.currentTimeMillis();
final long newTimestamp = mDevicePolicyManager.getLastNetworkLogRetrievalTime();
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
index e655d7b..a21d9e6 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
@@ -20,8 +20,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.test.ActivityInstrumentationTestCase2;
import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SanityTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SanityTest.java
new file mode 100644
index 0000000..28c7e25
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SanityTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+/**
+ * Basic sanity test to ensure some basic functionalities of work profile are working.
+ */
+public class SanityTest {
+ private static final ComponentName SIMPLE_APP_ACTIVITY =
+ new ComponentName(
+ "com.android.cts.launcherapps.simpleapp",
+ "com.android.cts.launcherapps.simpleapp.SimpleActivity");
+ /**
+ * Broadcast sent from com.android.cts.launcherapps.simpleapp.SimpleActivity.
+ */
+ private static final String ACTIVITY_LAUNCHED_ACTION =
+ "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION";
+
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ /**
+ * Verify that we can launch an app that installed in work profile only.
+ */
+ @Test
+ public void testLaunchAppInstalledInProfileOnly() throws Exception {
+ BlockingBroadcastReceiver receiver =
+ new BlockingBroadcastReceiver(mContext, ACTIVITY_LAUNCHED_ACTION);
+ try {
+ receiver.register();
+ Intent intent = new Intent();
+ intent.setComponent(SIMPLE_APP_ACTIVITY);
+ // Finish the activity after that.
+ intent.putExtra("finish", true);
+ mContext.startActivity(intent);
+ Intent receivedBroadcast = receiver.awaitForBroadcast();
+ assertNotNull(receivedBroadcast);
+ assertEquals(ACTIVITY_LAUNCHED_ACTION, receivedBroadcast.getAction());
+ } finally {
+ receiver.unregisterQuietly();
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java
index d033785..a773737 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java
@@ -27,7 +27,9 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mUserId = createUser();
+ if (isTestEnabled()) {
+ mUserId = createUser();
+ }
}
@Override
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index ba36fbf..84a08ee 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -71,6 +71,8 @@
private static final String FEATURE_TELEPHONY = "android.hardware.telephony";
private static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
+ private static final String SIMPLE_APP_APK = "CtsSimpleApp.apk";
+ private static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
private static final long TIMEOUT_USER_LOCKED_MILLIS = TimeUnit.SECONDS.toMillis(15);
@@ -870,6 +872,15 @@
}
}
+ public void testSanityCheck() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ // Install SimpleApp in work profile only and check activity in it can be launched.
+ installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
+ runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".SanityTest", mProfileUserId);
+ }
+
private void disableActivityForUser(String activityName, int userId)
throws DeviceNotAvailableException {
String command = "am start -W --user " + userId
diff --git a/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
index f76bf37..d4937aa 100644
--- a/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
+++ b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
@@ -28,6 +28,10 @@
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
+ <service android:name=".BatteryStatsBackgroundService" android:exported="true" />
+
+ <activity android:name=".BatteryStatsForegroundActivity" android:exported="true" />
+
<service android:name=".BatteryStatsWifiTransferTests$TransferService" android:exported="true" />
<service android:name=".SimpleForegroundService" android:exported="true" />
@@ -35,9 +39,7 @@
<service android:name=".SimpleJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
- <activity android:name=".SimpleActivity" android:label="BatteryStats Test Activity" />
-
- <activity android:name=".BatteryStatsWifiScanTests$WiFiScanActivity" android:label="BatteryStats Wifi scan Test Activity" />
+ <activity android:name=".SimpleActivity" android:label="BatteryStats Test Activity" android:exported="true" />
<service android:name=".BatteryStatsAuthenticator"
android:exported="false">
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java
new file mode 100644
index 0000000..496e61a
--- /dev/null
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts.device.batterystats;
+
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.KEY_ACTION;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.doAction;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.isAppInBackground;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.util.Log;
+
+import org.junit.Assert;
+
+/** An service (to be run as a background process) which performs one of a number of actions. */
+public class BatteryStatsBackgroundService extends IntentService {
+ private static final String TAG = BatteryStatsBackgroundService.class.getSimpleName();
+
+ public BatteryStatsBackgroundService() {
+ super(BatteryStatsBackgroundService.class.getName());
+ }
+
+ @Override
+ public void onHandleIntent(Intent intent) {
+ try {
+ if (!isAppInBackground(this)) {
+ Log.e(TAG, "BackgroundService is not a background process!");
+ Assert.fail("Test requires BackgroundService to be in background.");
+ }
+ } catch(ReflectiveOperationException ex) {
+ Log.w(TAG, "Couldn't determine if app is in background. Proceeding with test anyway.");
+ }
+
+ Log.i(TAG, "Starting action from background service");
+ doAction(this, intent.getStringExtra(KEY_ACTION));
+ }
+}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
new file mode 100644
index 0000000..ab20d87
--- /dev/null
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts.device.batterystats;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Log;
+
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class BatteryStatsBgVsFgActions {
+ private static final String TAG = BatteryStatsBgVsFgActions.class.getSimpleName();
+
+ public static final String KEY_ACTION = "action";
+ public static final String ACTION_JOB_SCHEDULE = "action.jobs";
+ public static final String ACTION_SYNC = "action.sync";
+ public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
+ public static final String ACTION_WIFI_DOWNLOAD = "action.wifi_download";
+ public static final String ACTION_WIFI_UPLOAD = "action.wifi_upload";
+
+
+ /** Perform the action specified by the given action code (see constants above). */
+ public static void doAction(Context ctx, String actionCode) {
+ if (actionCode == null) {
+ Log.e(TAG, "Intent was missing action.");
+ return;
+ }
+ sleep(100);
+ switch(actionCode) {
+ case ACTION_JOB_SCHEDULE:
+ doScheduleJob(ctx);
+ break;
+ case ACTION_SYNC:
+ doSync(ctx);
+ break;
+ case ACTION_WIFI_SCAN:
+ doWifiScan(ctx);
+ break;
+ case ACTION_WIFI_DOWNLOAD:
+ doWifiDownload(ctx);
+ break;
+ case ACTION_WIFI_UPLOAD:
+ doWifiUpload(ctx);
+ break;
+ default:
+ Log.e(TAG, "Intent had invalid action");
+ }
+ sleep(100);
+ }
+
+ private static void doScheduleJob(Context ctx) {
+ final ComponentName JOB_COMPONENT_NAME =
+ new ComponentName("com.android.server.cts.device.batterystats",
+ SimpleJobService.class.getName());
+ JobScheduler js = ctx.getSystemService(JobScheduler.class);
+ if (js == null) {
+ Log.e(TAG, "JobScheduler service not available");
+ return;
+ }
+ final JobInfo job = (new JobInfo.Builder(1, JOB_COMPONENT_NAME))
+ .setOverrideDeadline(0)
+ .build();
+ CountDownLatch latch = SimpleJobService.resetCountDownLatch();
+ js.schedule(job);
+ // Job starts in main thread so wait in another thread to see if job finishes.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ waitForReceiver(null, 3_000, latch, null);
+ return null;
+ }
+ }.execute();
+ }
+
+ private static void doSync(Context ctx) {
+ BatteryStatsAuthenticator.removeAllAccounts(ctx);
+ final Account account = BatteryStatsAuthenticator.getTestAccount();
+ // Create the test account.
+ BatteryStatsAuthenticator.ensureTestAccount(ctx);
+ // Force set is syncable.
+ ContentResolver.setMasterSyncAutomatically(true);
+ ContentResolver.setIsSyncable(account, BatteryStatsProvider.AUTHORITY, 1);
+
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ Log.v(TAG, "Starting sync");
+ BatteryStatsSyncAdapter.requestSync(account);
+ sleep(500);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception trying to sync", e);
+ }
+ BatteryStatsAuthenticator.removeAllAccounts(ctx);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ super.onPostExecute(aVoid);
+ Log.v(TAG, "Finished sync method");
+ // If ctx is an Activity, finish it when sync is done. If it's a service, don't.
+ if(ctx instanceof Activity){
+ ((Activity) ctx).finish();
+ }
+ }
+ }.execute();
+ }
+
+ private static void doWifiScan(Context ctx) {
+ IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ CountDownLatch onReceiveLatch = new CountDownLatch(1);
+ BroadcastReceiver receiver = registerReceiver(ctx, onReceiveLatch, intentFilter);
+ ctx.getSystemService(WifiManager.class).startScan();
+ waitForReceiver(ctx, 3_000, onReceiveLatch, receiver);
+ }
+
+ private static void doWifiDownload(Context ctx) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ BatteryStatsWifiTransferTests.download();
+ return null;
+ }
+ }.execute();
+ }
+
+ private static void doWifiUpload(Context ctx) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ BatteryStatsWifiTransferTests.upload();
+ return null;
+ }
+ }.execute();
+ }
+
+ /** Register receiver to determine when given action is complete. */
+ private static BroadcastReceiver registerReceiver(
+ Context ctx, CountDownLatch onReceiveLatch, IntentFilter intentFilter) {
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onReceiveLatch.countDown();
+ }
+ };
+ // run Broadcast receiver in a different thread since the foreground activity will wait.
+ HandlerThread handlerThread = new HandlerThread("br_handler_thread");
+ handlerThread.start();
+ Looper looper = handlerThread.getLooper();
+ Handler handler = new Handler(looper);
+ ctx.registerReceiver(receiver, intentFilter, null, handler);
+ return receiver;
+ }
+
+ /**
+ * Uses the receiver to wait until the action is complete. ctx and receiver may be null if no
+ * receiver is needed to be unregistered.
+ */
+ private static void waitForReceiver(Context ctx,
+ int maxWaitTimeMs, CountDownLatch latch, BroadcastReceiver receiver) {
+ try {
+ boolean didFinish = latch.await(maxWaitTimeMs, TimeUnit.MILLISECONDS);
+ if (didFinish) {
+ Log.v(TAG, "Finished performing action");
+ } else {
+ // This is not necessarily a problem. If we just want to make sure a count was
+ // recorded for the request, it doesn't matter if the action actually finished.
+ Log.w(TAG, "Did not finish in specified time.");
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted exception while awaiting action to finish", e);
+ }
+ if (ctx != null && receiver != null) {
+ ctx.unregisterReceiver(receiver);
+ }
+ }
+
+ /** Determines whether the package is running as a background process. */
+ public static boolean isAppInBackground(Context context) throws ReflectiveOperationException {
+ String pkgName = context.getPackageName();
+ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+ if (processes == null) {
+ return false;
+ }
+ for (ActivityManager.RunningAppProcessInfo r : processes){
+ // BatteryStatsImpl treats as background if procState is >=
+ // Activitymanager.PROCESS_STATE_IMPORTANT_BACKGROUND (corresponding
+ // to BatteryStats.PROCESS_STATE_BACKGROUND).
+ // Due to lack of permissions, only the current app should show up in the list of
+ // processes, which is desired in this case; but in case this changes later, we check
+ // that the package name matches anyway.
+ int processState = -1;
+ int backgroundCode = -1;
+ try {
+ processState = ActivityManager.RunningAppProcessInfo.class
+ .getField("processState").getInt(r);
+ backgroundCode = (Integer) ActivityManager.class
+ .getDeclaredField("PROCESS_STATE_IMPORTANT_BACKGROUND").get(null);
+ } catch (ReflectiveOperationException ex) {
+ Log.e(TAG, "Failed to get proc state info via reflection", ex);
+ throw ex;
+ }
+ if (processState < backgroundCode) { // if foreground process
+ for (String rpkg : r.pkgList) {
+ if (pkgName.equals(rpkg)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /** Puts the current thread to sleep. */
+ private static void sleep(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted exception while sleeping", e);
+ }
+ }
+}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
new file mode 100644
index 0000000..c41b244
--- /dev/null
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts.device.batterystats;
+
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions
+ .ACTION_JOB_SCHEDULE;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.ACTION_SYNC;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.KEY_ACTION;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.doAction;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.isAppInBackground;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import org.junit.Assert;
+
+/** An activity (to be run as a foreground process) which performs one of a number of actions. */
+public class BatteryStatsForegroundActivity extends Activity {
+ private static final String TAG = BatteryStatsForegroundActivity.class.getSimpleName();
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ Intent intent = this.getIntent();
+ if (intent == null) {
+ Log.e(TAG, "Intent was null.");
+ finish();
+ }
+ try {
+ if (isAppInBackground(this)) {
+ Log.e(TAG, "ForegroundActivity is a background process!");
+ Assert.fail("Test requires ForegroundActivity to be in foreground.");
+ }
+ } catch(ReflectiveOperationException ex) {
+ Log.w(TAG, "Couldn't determine if app is in foreground. Proceeding with test anyway");
+ }
+
+ String action = intent.getStringExtra(KEY_ACTION);
+ doAction(this, action);
+
+ // ACTION_SYNC will finish itself. Others get finished here.
+ if (!ACTION_SYNC.equals(action)) {
+ finish();
+ }
+ }
+}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java
index c619166..c40c950 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java
@@ -34,12 +34,7 @@
public void testForegroundService() throws Exception {
Intent intent = new Intent();
intent.setClass(mContext, SimpleForegroundService.class);
- Notification notification = new Notification.Builder(mContext, "Foreground Service")
- .setContentTitle("CTS Foreground")
- .setSmallIcon(android.R.drawable.ic_secure)
- .build();
- mContext.getSystemService(NotificationManager.class).startServiceInForeground(intent,
- 1, notification);
+ mContext.startForegroundService(intent);
Thread.sleep(3000);
}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiScanTests.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiScanTests.java
deleted file mode 100644
index 4bf8ec5..0000000
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiScanTests.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.server.cts.device.batterystats;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.InstrumentationRegistry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Used by BatteryStatsValidationTest.
- */
-@RunWith(AndroidJUnit4.class)
-public class BatteryStatsWifiScanTests {
- private CountDownLatch mResultsReceivedSignal;
- private WifiManager mWifiManager;
- private Context mContext;
- private boolean mHasFeature;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mHasFeature = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
- if (!mHasFeature) {
- return;
- }
- mWifiManager = mContext.getSystemService(WifiManager.class);
- mResultsReceivedSignal = new CountDownLatch(1);
- registerReceiver(mContext, mResultsReceivedSignal);
- }
-
- @Test
- public void testBackgroundScan() throws Exception {
- if (!mHasFeature) {
- return;
- }
- mWifiManager.startScan();
- mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
- }
-
- @Test
- public void testForegroundScan() throws Exception {
- if (!mHasFeature) {
- return;
- }
- WiFiScanActivity.mResultsReceivedSignal = mResultsReceivedSignal;
- Intent intent = new Intent(mContext, WiFiScanActivity.class);
- mContext.startActivity(intent);
- mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
- WiFiScanActivity.instance.finish();
- }
-
- static void registerReceiver(Context ctx, CountDownLatch onReceiveLatch) {
- ctx.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onReceiveLatch.countDown();
- }
- }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
- }
-
- public static class WiFiScanActivity extends Activity {
- private static CountDownLatch mResultsReceivedSignal;
- private static Activity instance;
-
- @Override
- public void onCreate(Bundle bundle) {
- instance = this;
- super.onCreate(bundle);
- BatteryStatsWifiScanTests.registerReceiver(this, mResultsReceivedSignal);
- getSystemService(WifiManager.class).startScan();
- }
- }
-}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java
index 394a070..1633301 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java
@@ -45,177 +45,60 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-/**
- * Used by BatteryStatsValidationTest.
- */
-@RunWith(AndroidJUnit4.class)
-public class BatteryStatsWifiTransferTests extends BatteryStatsDeviceTestBase {
+public class BatteryStatsWifiTransferTests {
private static final String TAG = "BatteryStatsWifiTransferTests";
- /** String extra to instruct whether to download or upload. */
- private static final String EXTRA_ACTION = "action";
- private static final String ACTION_DOWNLOAD = "download";
- private static final String ACTION_UPLOAD = "upload";
-
- /** Action to notify the test that wifi transfer is complete. */
- private static final String ACTION_TRANSFER_COMPLETE = "transfer_complete";
-
- /** String extra of any error encountered during wifi transfer. */
- private static final String EXTRA_TRANSFER_ERROR = "transfer_error";
-
private static final int READ_BUFFER_SIZE = 4096;
/** Server to send requests to. */
private static final String SERVER_URL = "https://developer.android.com/index.html";
- private Context mContext;
- private CountDownLatch mResultsReceivedSignal;
- private Intent mTransferService;
- private boolean mHasFeature;
- private volatile String mError;
+ public static String download() {
+ HttpURLConnection conn = null;
+ try {
+ URL url = new URL(SERVER_URL);
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setUseCaches(false);
+ conn.setRequestProperty("Accept-Encoding", "identity"); // Disable compression.
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mHasFeature = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
- if (!mHasFeature) {
- return;
- }
- mResultsReceivedSignal = new CountDownLatch(1);
- mTransferService = new Intent(mContext, TransferService.class);
- registerReceiver(mContext, mResultsReceivedSignal);
- }
+ InputStream in = new BufferedInputStream(conn.getInputStream());
+ byte[] data = new byte[READ_BUFFER_SIZE];
- @Test
- public void testBackgroundDownload() throws Exception {
- doBackgroundTransfer(ACTION_DOWNLOAD);
- }
-
- @Test
- public void testForegroundDownload() throws Exception {
- doForegroundTransfer(ACTION_DOWNLOAD);
- }
-
- @Test
- public void testBackgroundUpload() throws Exception {
- doBackgroundTransfer(ACTION_UPLOAD);
- }
-
- @Test
- public void testForegroundUpload() throws Exception {
- doForegroundTransfer(ACTION_UPLOAD);
- }
-
- private void doBackgroundTransfer(String action) throws Exception {
- if (!mHasFeature) {
- return;
- }
- mTransferService.putExtra(EXTRA_ACTION, action);
- mContext.startService(mTransferService);
- mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
- assertTrue("Got error: " + mError, mError == null);
- }
-
- private void doForegroundTransfer(String action) throws Exception {
- if (!mHasFeature) {
- return;
- }
- mTransferService.putExtra(EXTRA_ACTION, action);
- Notification notification =
- new Notification.Builder(mContext, "Wifi Transfer Foreground Service")
- .setContentTitle("Wifi Transfer Foreground")
- .setContentText("Wifi Transfer Foreground")
- .setSmallIcon(android.R.drawable.ic_secure)
- .build();
- mContext.getSystemService(NotificationManager.class).startServiceInForeground(mTransferService,
- 1, notification);
-
- mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
- assertTrue("Got error: " + mError, mError == null);
- }
-
- private void registerReceiver(Context ctx, CountDownLatch onReceiveLatch) {
- ctx.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mError = intent.getStringExtra(EXTRA_TRANSFER_ERROR);
- onReceiveLatch.countDown();
+ int total = 0;
+ int count;
+ while ((count = in.read(data)) != -1) {
+ total += count;
}
- }, new IntentFilter(ACTION_TRANSFER_COMPLETE));
- }
-
- public static class TransferService extends IntentService {
- public TransferService() {
- this(TransferService.class.getName());
+ Log.i(TAG, Integer.toString(total));
+ } catch (IOException e) {
+ Log.i(TAG, e.toString());
+ return "Caught exception";
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
}
+ return null;
+ }
- public TransferService(String name) {
- super(name);
+
+ public static String upload() {
+ HttpURLConnection conn = null;
+ try {
+ // Append a long query string.
+ char[] queryChars = new char[2*1024];
+ Arrays.fill(queryChars, 'a');
+ URL url = new URL(SERVER_URL + "?" + new String(queryChars));
+ conn = (HttpURLConnection) url.openConnection();
+ InputStream in = conn.getInputStream();
+ in.close();
+ } catch (IOException e) {
+ return "IO exception";
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
}
-
- @Override
- protected void onHandleIntent(Intent intent) {
- String error = null;
- switch (intent.getStringExtra(EXTRA_ACTION)) {
- case ACTION_DOWNLOAD:
- error = download();
- break;
- case ACTION_UPLOAD:
- error = upload();
- break;
- default:
- error = "Unknown action " + intent.getStringExtra(EXTRA_ACTION);
- }
- Intent localIntent = new Intent(ACTION_TRANSFER_COMPLETE);
- localIntent.putExtra(EXTRA_TRANSFER_ERROR, error);
- sendBroadcast(localIntent);
- }
-
- private String download() {
- HttpURLConnection conn = null;
- try {
- URL url = new URL(SERVER_URL);
- conn = (HttpURLConnection) url.openConnection();
- conn.setUseCaches(false);
- conn.setRequestProperty("Accept-Encoding", "identity"); // Disable compression.
-
- InputStream in = new BufferedInputStream(conn.getInputStream());
- byte[] data = new byte[READ_BUFFER_SIZE];
-
- int total = 0;
- int count;
- while ((count = in.read(data)) != -1) {
- total += count;
- }
- Log.i(TAG, Integer.toString(total));
- } catch (IOException e) {
- return "Caught exception";
- } finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- return null;
- }
-
- private String upload() {
- HttpURLConnection conn = null;
- try {
- // Append a long query string.
- char[] queryChars = new char[2*1024];
- Arrays.fill(queryChars, 'a');
- URL url = new URL(SERVER_URL + "?" + new String(queryChars));
- conn = (HttpURLConnection) url.openConnection();
- InputStream in = conn.getInputStream();
- in.close();
- } catch (IOException e) {
- return "IO exception";
- } finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- return null;
- }
- }
+ return null;
+ }
}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java
index b8d4507..ed21615 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java
@@ -16,6 +16,7 @@
package com.android.server.cts.device.batterystats;
+import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
@@ -67,6 +68,12 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
+ Notification notification = new Notification.Builder(this, "Foreground Service")
+ .setContentTitle("CTS Foreground")
+ .setSmallIcon(android.R.drawable.ic_secure)
+ .build();
+ startForeground(1, notification);
+
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index a499482..0fc22dc 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -28,12 +28,29 @@
private static final String DEVICE_SIDE_TEST_APK = "CtsBatteryStatsApp.apk";
private static final String DEVICE_SIDE_TEST_PACKAGE
= "com.android.server.cts.device.batterystats";
+ private static final String DEVICE_SIDE_BG_SERVICE_COMPONENT
+ = "com.android.server.cts.device.batterystats/.BatteryStatsBackgroundService";
+ private static final String DEVICE_SIDE_FG_ACTIVITY_COMPONENT
+ = "com.android.server.cts.device.batterystats/.BatteryStatsForegroundActivity";
private static final String DEVICE_SIDE_JOB_COMPONENT
= "com.android.server.cts.device.batterystats/.SimpleJobService";
private static final String DEVICE_SIDE_SYNC_COMPONENT
= "com.android.server.cts.device.batterystats.provider/"
+ "com.android.server.cts.device.batterystats";
+ // Low end of packet size. TODO: Get exact packet size
+ private static final int LOW_MTU = 1500;
+ // High end of packet size. TODO: Get exact packet size
+ private static final int HIGH_MTU = 2500;
+
+ // Constants from BatteryStatsBgVsFgActions.java (not directly accessible here).
+ public static final String KEY_ACTION = "action";
+ public static final String ACTION_JOB_SCHEDULE = "action.jobs";
+ public static final String ACTION_SYNC = "action.sync";
+ public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
+ public static final String ACTION_WIFI_DOWNLOAD = "action.wifi_download";
+ public static final String ACTION_WIFI_UPLOAD = "action.wifi_upload";
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -107,16 +124,61 @@
batteryOffScreenOn();
}
+ public void testJobBgVsFg() throws Exception {
+ batteryOnScreenOff();
+ installPackage(DEVICE_SIDE_TEST_APK, true);
+
+ // Foreground test.
+ executeForeground(ACTION_JOB_SCHEDULE);
+ Thread.sleep(4_000);
+ assertValueRange("jb", "", 6, 1, 1); // count
+ assertValueRange("jb", "", 8, 0, 0); // background_count
+
+ // Background test.
+ executeBackground(ACTION_JOB_SCHEDULE);
+ Thread.sleep(4_000);
+ assertValueRange("jb", "", 6, 2, 2); // count
+ assertValueRange("jb", "", 8, 1, 1); // background_count
+
+ batteryOffScreenOn();
+ }
+
+ public void testSyncBgVsFg() throws Exception {
+ batteryOnScreenOff();
+ installPackage(DEVICE_SIDE_TEST_APK, true);
+
+ // Foreground test.
+ executeForeground(ACTION_SYNC);
+ Thread.sleep(3_000);
+ // Allow one or two syncs in this time frame (not just one) due to unpredictable syncs.
+ assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 1, 2); // count
+ assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 8, 0, 0); // background_count
+
+ // Background test.
+ executeBackground(ACTION_SYNC);
+ Thread.sleep(3_000);
+ assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 2, 4); // count
+ assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 8, 1, 2); // background_count
+
+ batteryOffScreenOn();
+ }
+
public void testWifiScans() throws Exception {
batteryOnScreenOff();
installPackage(DEVICE_SIDE_TEST_APK, true);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiScanTests",
- "testBackgroundScan");
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiScanTests",
- "testForegroundScan");
+ // Foreground count test.
+ executeForeground(ACTION_WIFI_SCAN);
+ Thread.sleep(4_000);
+ assertValueRange("wfl", "", 7, 1, 1); // scan_count
+ assertValueRange("wfl", "", 11, 0, 0); // scan_count_bg
- assertValueRange("wfl", "", 7, 2, 2);
+ // Background count test.
+ executeBackground(ACTION_WIFI_SCAN);
+ Thread.sleep(6_000);
+ assertValueRange("wfl", "", 7, 2, 2); // scan_count
+ assertValueRange("wfl", "", 11, 1, 1); // scan_count_bg
+
batteryOffScreenOn();
}
@@ -189,23 +251,34 @@
batteryOnScreenOff();
installPackage(DEVICE_SIDE_TEST_APK, true);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
- "testForegroundDownload");
- long foregroundBytes = getDownloadedBytes();
- assertTrue(foregroundBytes > 0);
- long min = foregroundBytes + MIN_HTTP_HEADER_BYTES;
- long max = foregroundBytes + (10 * 1024); // Add some fuzzing.
- assertValueRange("nt", "", 6, min, max); // wifi_bytes_rx
- assertValueRange("nt", "", 11, 1, 40); // wifi_bytes_tx
+ final long FUZZ = 50 * 1024;
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
- "testBackgroundDownload");
- long backgroundBytes = getDownloadedBytes();
- assertTrue(backgroundBytes > 0);
- min += backgroundBytes + MIN_HTTP_HEADER_BYTES;
- max += backgroundBytes + (10 * 1024);
+ long prevBytes = getLongValue(getUid(), "nt", "", 6);
+
+ executeForeground(ACTION_WIFI_DOWNLOAD);
+ long downloadedBytes = getDownloadedBytes();
+ assertTrue(downloadedBytes > 0);
+ long min = prevBytes + downloadedBytes + MIN_HTTP_HEADER_BYTES;
+ long max = prevBytes + downloadedBytes + FUZZ; // Add some fuzzing.
assertValueRange("nt", "", 6, min, max); // wifi_bytes_rx
- assertValueRange("nt", "", 11, 2, 80); // wifi_bytes_tx
+ assertValueRange("nt", "", 10, min / HIGH_MTU, max / LOW_MTU); // wifi_packets_rx
+
+ // Do the background download
+ long prevBgBytes = getLongValue(getUid(), "nt", "", 20);
+ executeBackground(ACTION_WIFI_DOWNLOAD);
+ Thread.sleep(4000);
+ downloadedBytes = getDownloadedBytes();
+
+ long minBg = prevBgBytes + downloadedBytes + MIN_HTTP_HEADER_BYTES;
+ long maxBg = prevBgBytes + downloadedBytes + FUZZ;
+ assertValueRange("nt", "", 20, minBg, maxBg); // wifi_bytes_bg_rx
+ assertValueRange("nt", "", 24, minBg / HIGH_MTU, maxBg / LOW_MTU); // wifi_packets_bg_rx
+
+ // Also increases total wifi counts.
+ min += downloadedBytes + MIN_HTTP_HEADER_BYTES;
+ max += downloadedBytes + FUZZ;
+ assertValueRange("nt", "", 6, min, max); // wifi_bytes_rx
+ assertValueRange("nt", "", 10, min / HIGH_MTU, max / LOW_MTU); // wifi_packets_rx
batteryOffScreenOn();
}
@@ -217,33 +290,37 @@
batteryOnScreenOff();
installPackage(DEVICE_SIDE_TEST_APK, true);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
- "testForegroundUpload");
+ executeForeground(ACTION_WIFI_UPLOAD);
+ Thread.sleep(2000);
int min = MIN_HTTP_HEADER_BYTES + (2 * 1024);
int max = min + (6 * 1024); // Add some fuzzing.
assertValueRange("nt", "", 7, min, max); // wifi_bytes_tx
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
- "testBackgroundUpload");
- assertValueRange("nt", "", 7, min * 2, max * 2); // wifi_bytes_tx
+ executeBackground(ACTION_WIFI_UPLOAD);
+ Thread.sleep(4000);
+ assertValueRange("nt", "", 21, min * 2, max * 2); // wifi_bytes_bg_tx
batteryOffScreenOn();
}
+ private int getUid() throws Exception {
+ String uidLine = getDevice().executeShellCommand("cmd package list packages -U "
+ + DEVICE_SIDE_TEST_PACKAGE);
+ String[] uidLineParts = uidLine.split(":");
+ // 3rd entry is package uid
+ assertTrue(uidLineParts.length > 2);
+ int uid = Integer.parseInt(uidLineParts[2].trim());
+ assertTrue(uid > 10000);
+ return uid;
+ }
+
/**
* Verifies that the recorded time for the specified tag and name in the test package
* is within the specified range.
*/
private void assertValueRange(String tag, String optionalAfterTag,
int index, long min, long max) throws Exception {
- String uidLine = getDevice().executeShellCommand("cmd package list packages -U "
- + DEVICE_SIDE_TEST_PACKAGE);
- String[] uidLineParts = uidLine.split(":");
- // 3rd entry is package uid
- assertTrue(uidLineParts.length > 2);
- int uid = Integer.parseInt(uidLineParts[2].trim());
- assertTrue(uid > 10000);
-
+ int uid = getUid();
long value = getLongValue(uid, tag, optionalAfterTag, index);
assertTrue("Value " + value + " is less than min " + min, value >= min);
@@ -274,19 +351,49 @@
}
/**
+ * Runs a (background) service to perform the given action.
+ * @param actionValue one of the constants in BatteryStatsBgVsFgActions indicating the desired
+ * action to perform.
+ */
+ private void executeBackground(String actionValue) throws Exception {
+ allowBackgroundServices();
+ getDevice().executeShellCommand(String.format(
+ "am startservice -n '%s' -e %s %s",
+ DEVICE_SIDE_BG_SERVICE_COMPONENT, KEY_ACTION, actionValue));
+ }
+
+ /** Required to successfully start a background service from adb in O. */
+ private void allowBackgroundServices() throws Exception {
+ getDevice().executeShellCommand(String.format(
+ "cmd deviceidle tempwhitelist %s", DEVICE_SIDE_TEST_PACKAGE));
+ }
+
+ /**
+ * Runs an activity (in the foreground) to perform the given action.
+ * @param actionValue one of the constants in BatteryStatsBgVsFgActions indicating the desired
+ * action to perform.
+ */
+ private void executeForeground(String actionValue) throws Exception {
+ getDevice().executeShellCommand(String.format(
+ "am start -n '%s' -e %s %s",
+ DEVICE_SIDE_FG_ACTIVITY_COMPONENT, KEY_ACTION, actionValue));
+ }
+
+ /**
* Returns the bytes downloaded for the wifi transfer download tests.
*/
private long getDownloadedBytes() throws Exception {
String log = getDevice().executeShellCommand(
"logcat -d -s BatteryStatsWifiTransferTests -e '\\d+'");
String[] lines = log.split("\n");
+ long size = 0;
for (int i = lines.length - 1; i >= 0; i--) {
String[] parts = lines[i].split(":");
String num = parts[parts.length - 1].trim();
if (num.matches("\\d+")) {
- return Integer.parseInt(num);
+ size = Integer.parseInt(num);
}
}
- return 0;
+ return size;
}
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index 2fc0bc2..0f2965c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -143,6 +143,8 @@
assertBackgroundNetworkAccess(true);
setBatterySaverMode(true);
assertBackgroundNetworkAccess(false);
+ // Use setBatterySaverMode API to leave power-save mode instead of plugging in charger
+ setBatterySaverMode(false);
turnBatteryOn();
assertBackgroundNetworkAccess(true);
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 15daed9..b6857ae 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
@@ -100,6 +100,7 @@
protected ConnectivityManager mCm;
protected WifiManager mWfm;
protected int mUid;
+ private int mMyUid;
private String mMeteredWifi;
private MyServiceClient mServiceClient;
private boolean mHasWatch;
@@ -115,7 +116,7 @@
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mUid = getUid(TEST_APP2_PKG);
- final int myUid = getUid(mContext.getPackageName());
+ mMyUid = getUid(mContext.getPackageName());
mServiceClient = new MyServiceClient(mContext);
mServiceClient.bind();
mHasWatch = mContext.getPackageManager().hasSystemFeature(
@@ -128,7 +129,7 @@
mSupported = setUpActiveNetworkMeteringState();
Log.i(TAG, "Apps status on " + getName() + ":\n"
- + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n"
+ + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n"
+ "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid));
}
@@ -204,6 +205,21 @@
assertEquals("wrong status", toString(expectedStatus), actualStatus);
}
+ protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception {
+ final int actualStatus = mCm.getRestrictBackgroundStatus();
+ assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus));
+ }
+
+ protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception {
+ final int actualStatus = mCm.getRestrictBackgroundStatus();
+ if (expectedStatus != actualStatus) {
+ Log.d(TAG, "Expected: " + toString(expectedStatus)
+ + " but actual: " + toString(actualStatus));
+ return false;
+ }
+ return true;
+ }
+
protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception {
assertBackgroundState(); // Sanity check.
assertNetworkAccess(expectAllowed);
@@ -700,9 +716,9 @@
Log.i(TAG, "Setting Battery Saver Mode to " + enabled);
if (enabled) {
turnBatteryOff();
- executeSilentShellCommand("settings put global low_power 1");
+ executeSilentShellCommand("cmd power set-mode 1");
} else {
- executeSilentShellCommand("settings put global low_power 0");
+ executeSilentShellCommand("cmd power set-mode 0");
turnBatteryOn();
}
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index c3537c8..599a31c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -20,16 +20,21 @@
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
+import android.util.Log;
+
public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
private static final String[] REQUIRED_WHITELISTED_PACKAGES = {
"com.android.providers.downloads"
};
+ private boolean mIsDataSaverSupported;
+
@Override
public void setUp() throws Exception {
super.setUp();
+ mIsDataSaverSupported = isDataSaverSupported();
if (!isSupported()) return;
// Set initial state.
@@ -59,6 +64,32 @@
return setMeteredNetwork();
}
+ @Override
+ protected boolean isSupported() throws Exception {
+ if (!mIsDataSaverSupported) {
+ Log.i(TAG, "Skipping " + getClass() + "." + getName()
+ + "() because device does not support Data Saver Mode");
+ }
+ return mIsDataSaverSupported && super.isSupported();
+ }
+
+ /**
+ * As per CDD requirements, if the device doesn't support data saver mode then
+ * ConnectivityManager.getRestrictBackgroundStatus() will always return
+ * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if
+ * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns
+ * RESTRICT_BACKGROUND_STATUS_DISABLED or not.
+ */
+ private boolean isDataSaverSupported() throws Exception {
+ assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+ try {
+ setRestrictBackground(true);
+ return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+ } finally {
+ setRestrictBackground(false);
+ }
+ }
+
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
if (!isSupported()) return;
diff --git a/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java b/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java
index 3602076..d8b2816 100644
--- a/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java
+++ b/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java
@@ -20,96 +20,12 @@
*/
private static final String INSECURE_DEVICE_ADB_COMMAND = "find %s -type %s -perm /o=rwx 2>/dev/null";
- /**
- * Whitelist exceptions of allowed world accessbale char files under /dev
- */
- private static final Set<String> CHAR_DEV_EXCEPTIONS = new HashSet<String>(
- Arrays.asList(
- // All exceptions should be alphabetical and associated with a bug number.
- "/dev/adsprpc-smd", // b/11710243
- "/dev/alarm", // b/9035217
- "/dev/ashmem",
- "/dev/binder",
- "/dev/card0", // b/13159510
- "/dev/renderD128",
- "/dev/renderD129", // b/23798677
- "/dev/dri/card0", // b/13159510
- "/dev/dri/renderD128",
- "/dev/dri/renderD129", // b/23798677
- "/dev/felica", // b/11142586
- "/dev/felica_ant", // b/11142586
- "/dev/felica_cen", // b/11142586
- "/dev/felica_pon", // b/11142586
- "/dev/felica_rfs", // b/11142586
- "/dev/felica_rws", // b/11142586
- "/dev/felica_uicc", // b/11142586
- "/dev/full",
- "/dev/galcore",
- "/dev/genlock", // b/9035217
- "/dev/graphics/galcore",
- "/dev/hwbinder", // b/30886151
- "/dev/ion",
- "/dev/kgsl-2d0", // b/11271533
- "/dev/kgsl-2d1", // b/11271533
- "/dev/kgsl-3d0", // b/9035217
- "/dev/log/events", // b/9035217
- "/dev/log/main", // b/9035217
- "/dev/log/radio", // b/9035217
- "/dev/log/system", // b/9035217
- "/dev/mali0", // b/9106968
- "/dev/mali", // b/11142586
- "/dev/mm_interlock", // b/12955573
- "/dev/mm_isp", // b/12955573
- "/dev/mm_v3d", // b/12955573
- "/dev/msm_rotator", // b/9035217
- "/dev/null",
- "/dev/nvhost-as-gpu",
- "/dev/nvhost-ctrl", // b/9088251
- "/dev/nvhost-ctrl-gpu",
- "/dev/nvhost-dbg-gpu",
- "/dev/nvhost-gpu",
- "/dev/nvhost-gr2d", // b/9088251
- "/dev/nvhost-gr3d", // b/9088251
- "/dev/nvhost-tsec",
- "/dev/nvhost-prof-gpu",
- "/dev/nvhost-vic",
- "/dev/nvmap", // b/9088251
- "/dev/pmsg0", // b/31857082
- "/dev/ptmx", // b/9088251
- "/dev/pvrsrvkm", // b/9108170
- "/dev/pvr_sync",
- "/dev/quadd",
- "/dev/random",
- "/dev/snfc_cen", // b/11142586
- "/dev/snfc_hsel", // b/11142586
- "/dev/snfc_intu_poll", // b/11142586
- "/dev/snfc_rfs", // b/11142586
- "/dev/tegra-throughput",
- "/dev/tiler", // b/9108170
- "/dev/tty",
- "/dev/urandom",
- "/dev/ump", // b/11142586
- "/dev/xt_qtaguid", // b/9088251
- "/dev/zero",
- "/dev/fimg2d", // b/10428016
- "/dev/mobicore-user" // b/10428016
- ));
-
@Override
protected void setUp() throws Exception {
super.setUp();
mDevice = getDevice();
}
- public void testAllCharacterDevicesAreSecure() throws DeviceNotAvailableException {
- Set <String> insecure = getAllInsecureDevicesInDirAndSubdir("/dev", "c");
- Set <String> insecurePts = getAllInsecureDevicesInDirAndSubdir("/dev/pts", "c");
- insecure.removeAll(CHAR_DEV_EXCEPTIONS);
- insecure.removeAll(insecurePts);
- assertTrue("Found insecure character devices: " + insecure.toString(),
- insecure.isEmpty());
- }
-
public void testAllBlockDevicesAreSecure() throws Exception {
Set<String> insecure = getAllInsecureDevicesInDirAndSubdir("/dev", "b");
assertTrue("Found insecure block devices: " + insecure.toString(),
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 767939a..46779de 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -235,16 +235,25 @@
}
}
- private boolean isFullTrebleDevice() throws Exception {
- return PropertyUtil.getFirstApiLevel(mDevice) > 25;
+ // NOTE: cts/tools/selinux depends on this method. Rename/change with caution.
+ /**
+ * Returns {@code true} if this device is required to be a full Treble device.
+ */
+ public static boolean isFullTrebleDevice(ITestDevice device)
+ throws DeviceNotAvailableException {
+ return PropertyUtil.getFirstApiLevel(device) > 25;
+ }
+
+ private boolean isFullTrebleDevice() throws DeviceNotAvailableException {
+ return isFullTrebleDevice(mDevice);
}
/**
* Asserts that no vendor domains are exempted from the prohibition on Binder use.
*
- * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
- * during Android O development. This test will be removed before Android O.
- * TODO(b/35870313): Remove this test once b/35870313 is fixed.
+ * <p>NOTE: binder_in_vendor_violators attribute is only there to help bring up Treble devices.
+ * It offers a convenient way to temporarily bypass the prohibition on Binder use in vendor
+ * domains. This attribute must not be used on production Treble devices.
*/
public void testNoExemptionsForBinderInVendorBan() throws Exception {
if (!isFullTrebleDevice()) {
@@ -264,9 +273,10 @@
* Asserts that no domains are exempted from the prohibition on initiating socket communications
* between core and vendor domains.
*
- * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
- * during Android O development. This test will be removed before Android O.
- * TODO(b/36577153): Remove this test once b/36577153 is fixed.
+ * <p>NOTE: socket_between_core_and_vendor_violators attribute is only there to help bring up
+ * Treble devices. It offers a convenient way to temporarily bypass the prohibition on
+ * initiating socket communications between core and vendor domains. This attribute must not be
+ * used on production Treble devices.
*/
public void testNoExemptionsForSocketsBetweenCoreAndVendorBan() throws Exception {
if (!isFullTrebleDevice()) {
@@ -286,52 +296,25 @@
/**
* Asserts that no vendor domains are exempted from the prohibition on directly
- * accessing /data outside /data/vendor.
- *
- * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
- * during Android O development. This test will be removed before Android O.
- * TODO(b/34980020): Remove this test once b/34980020 is fixed.
- */
- public void testNoExemptionsForCoreDataInVendor() throws Exception {
+ * executing binaries from /system.
+ * */
+ public void testNoExemptionsForVendorExecutingCore() throws Exception {
if (!isFullTrebleDevice()) {
return;
}
Set<String> types =
sepolicyAnalyzeGetTypesAssociatedWithAttribute(
- "coredata_in_vendor_violators");
+ "vendor_executes_system_violators");
if (!types.isEmpty()) {
List<String> sortedTypes = new ArrayList<>(types);
Collections.sort(sortedTypes);
- fail("Policy exempts domains from ban on vendor domains accessing data partition"
- + " outside /data/vendor: " + sortedTypes);
+ fail("Policy exempts vendor domains from ban on executing files in /system: "
+ + sortedTypes);
}
}
/**
- * Asserts that no core domains are exempted from the prohibition on directly
- * accessing /data/vendor.
- *
- * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
- * during Android O development. This test will be removed before Android O.
- * TODO(b/34980020): Remove this test once b/34980020 is fixed.
- */
- public void testNoExemptionsForVendorDataInCore() throws Exception {
- if (!isFullTrebleDevice()) {
- return;
- }
-
- Set<String> types =
- sepolicyAnalyzeGetTypesAssociatedWithAttribute(
- "vendordata_in_core_violators");
- if (!types.isEmpty()) {
- List<String> sortedTypes = new ArrayList<>(types);
- Collections.sort(sortedTypes);
- fail("Policy exempts domains from ban on core domains accessing vendor data"
- + " in /data/vendor: " + sortedTypes);
- }
- }
- /**
* Tests that mlstrustedsubject does not include untrusted_app
* and that mlstrustedobject does not include app_data_file.
* This helps prevent circumventing the per-user isolation of
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
index ff9e62b..3a50232 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
@@ -24,7 +24,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
-LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
+LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util \
+ platform-test-annotations-host
LOCAL_CTS_TEST_PACKAGE := android.server
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index 9dda45a..d7800c4 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -59,6 +59,10 @@
android:taskAffinity="nobody.but.TranslucentActivity"
android:exported="true"
/>
+ <activity android:name=".DialogWhenLargeActivity"
+ android:exported="true"
+ android:theme="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge"
+ />
<activity android:name=".NoRelaunchActivity"
android:resizeableActivity="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|fontScale"
@@ -86,6 +90,14 @@
android:exported="true"
android:taskAffinity="nobody.but.PipActivity"
/>
+ <activity android:name=".PipActivity2"
+ android:resizeableActivity="false"
+ android:supportsPictureInPicture="true"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="true"
+ android:taskAffinity="nobody.but.PipActivity2"
+ />
+
<activity android:name=".AlwaysFocusablePipActivity"
android:theme="@style/Theme.Transparent"
android:resizeableActivity="false"
@@ -321,6 +333,11 @@
android:permission="android.permission.BIND_VOICE_INTERACTION"
android:exported="true" />
+ <activity android:name=".SplashscreenActivity"
+ android:taskAffinity="nobody.but.SplashscreenActivity"
+ android:theme="@style/SplashscreenTheme"
+ android:exported="true" />
+
<service android:name="com.android.cts.verifier.vr.MockVrListenerService"
android:exported="true"
android:enabled="true"
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/colors.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/colors.xml
new file mode 100644
index 0000000..2a51310
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/colors.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2017 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>
+ <drawable name="red">#ff0000</drawable>
+</resources>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
index 7fc6725..5068ea9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
@@ -40,4 +40,7 @@
<style name="NoPreview">
<item name="android:windowDisablePreview">true</item>
</style>
+ <style name="SplashscreenTheme" parent="@android:style/Theme.Material.NoActionBar">
+ <item name="android:windowSplashscreenContent">@drawable/red</item>
+ </style>
</resources>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DialogWhenLargeActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DialogWhenLargeActivity.java
new file mode 100644
index 0000000..139c648
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DialogWhenLargeActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.cts;
+
+/**
+ * Activity with DialogWhenLarge Theme.
+ */
+public class DialogWhenLargeActivity extends AbstractLifecycleLogActivity {
+ private static final String TAG = DialogWhenLargeActivity.class.getSimpleName();
+ @Override
+ protected String getTag() {
+ return TAG;
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity2.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity2.java
new file mode 100644
index 0000000..53b4f75
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity2.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 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.cts;
+
+/**
+ * A secondary activity that has the same behavior as {@link PipActivity}.
+ */
+public class PipActivity2 extends PipActivity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SplashscreenActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SplashscreenActivity.java
new file mode 100644
index 0000000..22391bd
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SplashscreenActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+
+/**
+ * Activity that shows a custom splashscreen when being launched.
+ */
+public class SplashscreenActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Make sure splash screen is visible. The test won't take 5 seconds because the condition
+ // such that we can dump the state will trigger much earlier and then the test will just
+ // kill us.
+ SystemClock.sleep(5000);
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
index a31e985..8374f7c 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
@@ -18,8 +18,6 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
-import static android.hardware.display.DisplayManager
- .VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
import android.app.Activity;
import android.content.Intent;
@@ -42,8 +40,6 @@
private static final int DEFAULT_DENSITY_DPI = 160;
private static final String KEY_DENSITY_DPI = "density_dpi";
- private static final String KEY_CAN_SHOW_WITH_INSECURE_KEYGUARD
- = "can_show_with_insecure_keyguard";
private static final String KEY_PUBLIC_DISPLAY = "public_display";
private static final String KEY_RESIZE_DISPLAY = "resize_display";
private static final String KEY_COUNT = "count";
@@ -165,20 +161,13 @@
int flags = 0;
- final boolean canShowWithInsecureKeyguard
- = entry.extras.getBoolean(KEY_CAN_SHOW_WITH_INSECURE_KEYGUARD);
- if (canShowWithInsecureKeyguard) {
- flags |= VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
- }
-
final boolean publicDisplay = entry.extras.getBoolean(KEY_PUBLIC_DISPLAY);
if (publicDisplay) {
flags |= VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
}
Log.d(TAG, "createVirtualDisplay: " + width + "x" + height + ", dpi: "
- + densityDpi + ", canShowWithInsecureKeyguard=" + canShowWithInsecureKeyguard
- + ", publicDisplay=" + publicDisplay);
+ + densityDpi + ", publicDisplay=" + publicDisplay);
try {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(
"VirtualDisplay" + mVirtualDisplays.size(), width,
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
index a7d4042..add7e42 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
@@ -40,12 +40,12 @@
private ConfigurationChangeObserver() {
}
- private boolean findConfigurationChange(String activityName)
+ private boolean findConfigurationChange(String activityName, String logSeparator)
throws DeviceNotAvailableException, InterruptedException {
int tries = 0;
boolean observedChange = false;
while (tries < 5 && !observedChange) {
- final String[] lines = getDeviceLogsForComponent(activityName);
+ final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
log("Looking at logcat");
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
@@ -72,16 +72,18 @@
launchActivityInStack(TEST_ACTIVITY_NAME, FREEFORM_WORKSPACE_STACK_ID);
setDeviceRotation(0);
- clearLogcat();
+ String logSeparator = clearLogcat();
resizeActivityTask(TEST_ACTIVITY_NAME, 0, 0, 100, 100);
ConfigurationChangeObserver c = new ConfigurationChangeObserver();
- final boolean reportedSizeAfterResize = c.findConfigurationChange(TEST_ACTIVITY_NAME);
+ final boolean reportedSizeAfterResize = c.findConfigurationChange(TEST_ACTIVITY_NAME,
+ logSeparator);
assertTrue("Expected to observe configuration change when resizing",
reportedSizeAfterResize);
- clearLogcat();
+ logSeparator = clearLogcat();
setDeviceRotation(2);
- final boolean reportedSizeAfterRotation = c.findConfigurationChange(TEST_ACTIVITY_NAME);
+ final boolean reportedSizeAfterRotation = c.findConfigurationChange(TEST_ACTIVITY_NAME,
+ logSeparator);
assertFalse("Not expected to observe configuration change after flip rotation",
reportedSizeAfterRotation);
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
index 697143f..c89b9c4 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -18,9 +18,15 @@
import static android.server.cts.ActivityManagerState.STATE_RESUMED;
+import android.platform.test.annotations.Presubmit;
+
import java.lang.Exception;
import java.lang.String;
+import static com.android.ddmlib.Log.LogLevel.INFO;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
/**
* Build: mmma -j32 cts/hostsidetests/services
* Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.ActivityManagerActivityVisibilityTests
@@ -36,6 +42,10 @@
private static final String MOVE_TASK_TO_BACK_ACTIVITY_NAME = "MoveTaskToBackActivity";
public void testVisibleBehindHomeActivity() throws Exception {
+ if (noHomeScreen()) {
+ return;
+ }
+
launchActivity(VISIBLE_BEHIND_ACTIVITY);
mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY,
FULLSCREEN_WORKSPACE_STACK_ID);
@@ -65,6 +75,10 @@
}
public void testVisibleBehindOtherActivity_OverHome() throws Exception {
+ if (noHomeScreen()) {
+ return;
+ }
+
executeShellCommand(getAmStartCmdOverHome(VISIBLE_BEHIND_ACTIVITY));
mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY);
executeShellCommand(getAmStartCmdOverHome(TRANSLUCENT_ACTIVITY));
@@ -97,6 +111,10 @@
* fullscreen stack over the home activity.
*/
public void testTranslucentActivityOnTopOfHome() throws Exception {
+ if (noHomeScreen()) {
+ return;
+ }
+
launchHomeActivity();
launchActivity(TRANSLUCENT_ACTIVITY);
@@ -130,6 +148,11 @@
}
public void testTranslucentActivityOverDockedStack() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
@@ -145,6 +168,7 @@
mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY_NAME, true);
}
+ @Presubmit
public void testTurnScreenOnActivity() throws Exception {
sleepDevice();
launchActivity(TURN_SCREEN_ON_ACTIVITY_NAME);
@@ -153,6 +177,11 @@
}
public void testFinishActivityInNonFocusedStack() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
// Launch two activities in docked stack.
launchActivityInDockStack(LAUNCHING_ACTIVITY);
getLaunchActivityBuilder().setTargetActivityName(BROADCAST_RECEIVER_ACTIVITY).execute();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
index b31fb16..f6df4a8 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
@@ -77,7 +77,8 @@
private void startActivityAndVerifyResult(final String entryActivity,
final String actualActivity, boolean shouldStart) throws Exception {
- clearLogcat();
+ // See TODO below
+ // final String logSeparator = clearLogcat();
// Pass in different data only when cold starting. This is to make the intent
// different in subsequent warm/hot launches, so that the entrypoint alias
@@ -96,7 +97,7 @@
// still catch most failures.
// Verify adb logcat log
- //verifyLogcat(actualActivity, shouldStart);
+ //verifyLogcat(actualActivity, shouldStart, logSeparator);
}
private static final Pattern sNotStartedWarningPattern = Pattern.compile(
@@ -149,12 +150,12 @@
private static final Pattern sDisplayTimePattern =
Pattern.compile("(.+): Displayed (.*): (\\+{0,1})([0-9]+)ms(.*)");
- void verifyLogcat(String actualActivityName, boolean shouldStart)
+ void verifyLogcat(String actualActivityName, boolean shouldStart, String logSeparator)
throws DeviceNotAvailableException {
int displayCount = 0;
String activityName = null;
- for (String line : getDeviceLogsForComponent("ActivityManager")) {
+ for (String line : getDeviceLogsForComponent("ActivityManager", logSeparator)) {
line = line.trim();
Matcher matcher = sDisplayTimePattern.matcher(line);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
index 7c3f39a..31f82ac 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -17,6 +17,8 @@
import static android.server.cts.ActivityManagerState.STATE_RESUMED;
+import android.platform.test.annotations.Presubmit;
+
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.log.LogUtil.CLog;
@@ -24,6 +26,8 @@
import java.util.ArrayList;
import java.util.List;
+import static android.server.cts.ActivityAndWindowManagersState.dpToPx;
+
/**
* Build: mmma -j32 cts/hostsidetests/services
* Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.ActivityManagerAppConfigurationTests
@@ -34,9 +38,13 @@
private static final String PORTRAIT_ACTIVITY_NAME = "PortraitOrientationActivity";
private static final String LANDSCAPE_ACTIVITY_NAME = "LandscapeOrientationActivity";
private static final String NIGHT_MODE_ACTIVITY = "NightModeActivity";
+ private static final String DIALOG_WHEN_LARGE_ACTIVITY = "DialogWhenLargeActivity";
private static final String EXTRA_LAUNCH_NEW_TASK = "launch_new_task";
+ private static final int SMALL_WIDTH_DP = 426;
+ private static final int SMALL_HEIGHT_DP = 320;
+
/**
* Tests that the WindowManager#getDefaultDisplay() and the Configuration of the Activity
* has an updated size when the Activity is resized from fullscreen to docked state.
@@ -47,11 +55,20 @@
* docked state.
*/
public void testConfigurationUpdatesWhenResizedFromFullscreen() throws Exception {
- launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
- final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+ return;
+ }
+ String logSeparator = clearLogcat();
+ launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+ final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
+
+ logSeparator = clearLogcat();
moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
- final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
assertSizesAreSane(fullscreenSizes, dockedSizes);
}
@@ -61,11 +78,20 @@
* from docked state to fullscreen (reverse).
*/
public void testConfigurationUpdatesWhenResizedFromDockedStack() throws Exception {
- launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
- final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+ return;
+ }
+ String logSeparator = clearLogcat();
+ launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
+ final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
+
+ logSeparator = clearLogcat();
moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
- final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
assertSizesAreSane(fullscreenSizes, dockedSizes);
}
@@ -75,8 +101,10 @@
*/
public void testConfigurationUpdatesWhenRotatingWhileFullscreen() throws Exception {
setDeviceRotation(0);
+ final String logSeparator = clearLogcat();
launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
- final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
rotateAndCheckSizes(initialSizes);
}
@@ -85,8 +113,15 @@
* Same as {@link #testConfigurationUpdatesWhenRotatingWhileFullscreen()} but when the Activity
* is in the docked stack.
*/
+ @Presubmit
public void testConfigurationUpdatesWhenRotatingWhileDocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
setDeviceRotation(0);
+ final String logSeparator = clearLogcat();
launchActivityInDockStack(LAUNCHING_ACTIVITY);
// Launch our own activity to side in case Recents (or other activity to side) doesn't
// support rotation.
@@ -94,7 +129,8 @@
.execute();
// Launch target activity in docked stack.
getLaunchActivityBuilder().setTargetActivityName(RESIZEABLE_ACTIVITY_NAME).execute();
- final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
rotateAndCheckSizes(initialSizes);
}
@@ -104,19 +140,26 @@
* is launched to side from docked stack.
*/
public void testConfigurationUpdatesWhenRotatingToSideFromDocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
setDeviceRotation(0);
+ final String logSeparator = clearLogcat();
launchActivityInDockStack(LAUNCHING_ACTIVITY);
getLaunchActivityBuilder().setToSide(true).setTargetActivityName(RESIZEABLE_ACTIVITY_NAME)
.execute();
- final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
rotateAndCheckSizes(initialSizes);
}
private void rotateAndCheckSizes(ReportedSizes prevSizes) throws Exception {
for (int rotation = 3; rotation >= 0; --rotation) {
- clearLogcat();
+ final String logSeparator = clearLogcat();
final int actualStackId = mAmWmState.getAmState().getTaskByActivityName(
RESIZEABLE_ACTIVITY_NAME).mStackId;
final int displayId = mAmWmState.getAmState().getStackById(actualStackId).mDisplayId;
@@ -131,7 +174,8 @@
return;
}
- final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
assertSizesRotate(prevSizes, rotatedSizes);
prevSizes = rotatedSizes;
}
@@ -148,6 +192,7 @@
/**
* Same as {@link #testSameConfigurationFullSplitFullRelaunch} but without relaunch.
*/
+ @Presubmit
public void testSameConfigurationFullSplitFullNoRelaunch() throws Exception {
moveActivityFullSplitFull(RESIZEABLE_ACTIVITY_NAME);
}
@@ -160,14 +205,22 @@
* Asserts that initial and final reported sizes in fullscreen stack are the same.
*/
private void moveActivityFullSplitFull(String activityName) throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
// Launch to fullscreen stack and record size.
+ String logSeparator = clearLogcat();
launchActivityInStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
- final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName);
+ final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName,
+ logSeparator);
final Rectangle displayRect = getDisplayRect(activityName);
// Move to docked stack.
+ logSeparator = clearLogcat();
moveActivityToStack(activityName, DOCKED_STACK_ID);
- final ReportedSizes dockedSizes = getActivityDisplaySize(activityName);
+ final ReportedSizes dockedSizes = getActivityDisplaySize(activityName, logSeparator);
assertSizesAreSane(initialFullscreenSizes, dockedSizes);
// Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
// will come up.
@@ -177,11 +230,13 @@
// Resize docked stack to fullscreen size. This will trigger activity relaunch with
// non-empty override configuration corresponding to fullscreen size.
+ logSeparator = clearLogcat();
runCommandAndPrintOutput("am stack resize " + DOCKED_STACK_ID + " 0 0 "
+ displayRect.width + " " + displayRect.height);
// Move activity back to fullscreen stack.
moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
- final ReportedSizes finalFullscreenSizes = getActivityDisplaySize(activityName);
+ final ReportedSizes finalFullscreenSizes = getActivityDisplaySize(activityName,
+ logSeparator);
// After activity configuration was changed twice it must report same size as original one.
assertSizesAreSame(initialFullscreenSizes, finalFullscreenSizes);
@@ -203,6 +258,26 @@
}
/**
+ * Tests that an activity with the DialogWhenLarge theme can transform properly when in split
+ * screen.
+ */
+ @Presubmit
+ public void testDialogWhenLargeSplitSmall() throws Exception {
+ launchActivityInStack(DIALOG_WHEN_LARGE_ACTIVITY, DOCKED_STACK_ID);
+ final ActivityManagerState.ActivityStack stack = mAmWmState.getAmState()
+ .getStackById(DOCKED_STACK_ID);
+ final WindowManagerState.Display display =
+ mAmWmState.getWmState().getDisplay(stack.mDisplayId);
+ final int density = display.getDpi();
+ final int smallWidthPx = dpToPx(SMALL_WIDTH_DP, density);
+ final int smallHeightPx = dpToPx(SMALL_HEIGHT_DP, density);
+
+ runCommandAndPrintOutput("am stack resize " + DOCKED_STACK_ID + " 0 0 "
+ + smallWidthPx + " " + smallHeightPx);
+ mAmWmState.waitForValidState(mDevice, DIALOG_WHEN_LARGE_ACTIVITY, DOCKED_STACK_ID);
+ }
+
+ /**
* Test that device handles consequent requested orientations and displays the activities.
*/
public void testFullscreenAppOrientationRequests() throws Exception {
@@ -319,9 +394,15 @@
* Asserts that initial and final reported sizes in docked stack are the same.
*/
private void moveActivitySplitFullSplit(String activityName) throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
// Launch to docked stack and record size.
+ String logSeparator = clearLogcat();
launchActivityInStack(activityName, DOCKED_STACK_ID);
- final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName);
+ final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName, logSeparator);
// Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
// will come up.
launchActivityInStack(activityName, DOCKED_STACK_ID);
@@ -329,13 +410,15 @@
false /* compareTaskAndStackBounds */);
// Move to fullscreen stack.
+ logSeparator = clearLogcat();
moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
- final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName);
+ final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName, logSeparator);
assertSizesAreSane(fullscreenSizes, initialDockedSizes);
// Move activity back to docked stack.
+ logSeparator = clearLogcat();
moveActivityToStack(activityName, DOCKED_STACK_ID);
- final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName);
+ final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName, logSeparator);
// After activity configuration was changed twice it must report same size as original one.
assertSizesAreSame(initialDockedSizes, finalDockedSizes);
@@ -396,10 +479,11 @@
assertEquals(firstSize.smallestWidthDp, secondSize.smallestWidthDp);
}
- private ReportedSizes getActivityDisplaySize(String activityName) throws Exception {
+ private ReportedSizes getActivityDisplaySize(String activityName, String logSeparator)
+ throws Exception {
mAmWmState.computeState(mDevice, new String[] { activityName },
false /* compareTaskAndStackBounds */);
- final ReportedSizes details = getLastReportedSizesForActivity(activityName);
+ final ReportedSizes details = getLastReportedSizesForActivity(activityName, logSeparator);
assertNotNull(details);
return details;
}
@@ -431,8 +515,6 @@
* Test launching an activity which requests specific UI mode during creation.
*/
public void testLaunchWithUiModeChange() throws Exception {
- clearLogcat();
-
// Launch activity that changes UI mode and handles this configuration change.
launchActivity(NIGHT_MODE_ACTIVITY);
mAmWmState.waitForActivityState(mDevice, NIGHT_MODE_ACTIVITY, STATE_RESUMED);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
index ede2b87..cf4f803 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
@@ -16,7 +16,13 @@
package android.server.cts;
+import android.platform.test.annotations.Presubmit;
+
import static android.server.cts.ActivityManagerState.STATE_RESUMED;
+import static android.server.cts.StateLogger.logE;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.log.LogUtil.CLog;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -50,14 +56,16 @@
testRotation(NO_RELAUNCH_ACTIVITY_NAME, 2, 0, 0);
}
+ @Presubmit
public void testChangeFontScaleRelaunch() throws Exception {
// Should relaunch and receive no onConfigurationChanged()
- testChangeFontScale(TEST_ACTIVITY_NAME, true);
+ testChangeFontScale(TEST_ACTIVITY_NAME, true /* relaunch */);
}
+ @Presubmit
public void testChangeFontScaleNoRelaunch() throws Exception {
// Should receive onConfigurationChanged() and no relaunch
- testChangeFontScale(NO_RELAUNCH_ACTIVITY_NAME, false);
+ testChangeFontScale(NO_RELAUNCH_ACTIVITY_NAME, false /* relaunch */);
}
private void testRotation(
@@ -68,14 +76,27 @@
final String[] waitForActivitiesVisible = new String[] {activityName};
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- setDeviceRotation(4 - rotationStep);
+ final int initialRotation = 4 - rotationStep;
+ setDeviceRotation(initialRotation);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+ final int actualStackId = mAmWmState.getAmState().getTaskByActivityName(
+ activityName).mStackId;
+ final int displayId = mAmWmState.getAmState().getStackById(actualStackId).mDisplayId;
+ final int newDeviceRotation = getDeviceRotation(displayId);
+ if (newDeviceRotation == INVALID_DEVICE_ROTATION) {
+ CLog.logAndDisplay(LogLevel.WARN, "Got an invalid device rotation value. "
+ + "Continuing the test despite of that, but it is likely to fail.");
+ } else if (newDeviceRotation != initialRotation) {
+ CLog.logAndDisplay(LogLevel.INFO, "This device doesn't support user rotation "
+ + "mode. Not continuing the rotation checks.");
+ return;
+ }
for (int rotation = 0; rotation < 4; rotation += rotationStep) {
- clearLogcat();
+ final String logSeparator = clearLogcat();
setDeviceRotation(rotation);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange);
+ assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange, logSeparator);
}
}
@@ -89,10 +110,11 @@
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
for (float fontScale = 0.85f; fontScale <= 1.3f; fontScale += 0.15f) {
- clearLogcat();
+ final String logSeparator = clearLogcat();
setFontScale(fontScale);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
- assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1);
+ assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1,
+ logSeparator);
}
}
@@ -101,29 +123,30 @@
* must be recreated and its asset sequence number must be incremented.
*/
public void testUpdateApplicationInfo() throws Exception {
- clearLogcat();
+ final String firstLogSeparator = clearLogcat();
// Launch an activity that prints applied config.
launchActivity(TEST_ACTIVITY_NAME);
- final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME);
- clearLogcat();
+ final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME, firstLogSeparator);
+ final String logSeparator = clearLogcat();
// Update package info.
executeShellCommand("am update-appinfo all " + componentName);
mAmWmState.waitForWithAmState(mDevice, (amState) -> {
// Wait for activity to be resumed and asset seq number to be updated.
try {
- return readAssetSeqNumber(TEST_ACTIVITY_NAME) == assetSeq + 1
+ return readAssetSeqNumber(TEST_ACTIVITY_NAME, logSeparator) == assetSeq + 1
&& amState.hasActivityState(TEST_ACTIVITY_NAME, STATE_RESUMED);
} catch (Exception e) {
+ logE("Error waiting for valid state: " + e.getMessage());
return false;
}
}, "Waiting asset sequence number to be updated and for activity to be resumed.");
// Check if activity is relaunched and asset seq is updated.
assertRelaunchOrConfigChanged(TEST_ACTIVITY_NAME, 1 /* numRelaunch */,
- 0 /* numConfigChange */);
- final int newAssetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME);
+ 0 /* numConfigChange */, logSeparator);
+ final int newAssetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME, logSeparator);
assertEquals("Asset sequence number must be incremented.", assetSeq + 1, newAssetSeq);
}
@@ -131,8 +154,8 @@
"(.+): Configuration: \\{(.*) as.(\\d+)(.*)\\}");
/** Read asset sequence number in last applied configuration from logs. */
- private int readAssetSeqNumber(String activityName) throws Exception {
- final String[] lines = getDeviceLogsForComponent(activityName);
+ private int readAssetSeqNumber(String activityName, String logSeparator) throws Exception {
+ final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
final Matcher matcher = sConfigurationPattern.matcher(line);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
index afe4d7e..cda836f 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -15,6 +15,8 @@
*/
package android.server.cts;
+import android.platform.test.annotations.Presubmit;
+
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -345,6 +347,7 @@
/**
* Tests launching an activity on virtual display.
*/
+ @Presubmit
public void testLaunchActivityOnSecondaryDisplay() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -352,6 +355,7 @@
final DisplayState newDisplay = new VirtualDisplayBuilder(this).build();
// Launch activity on new secondary display.
+ final String logSeparator = clearLogcat();
launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
@@ -369,7 +373,8 @@
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
// Check that activity config corresponds to display config.
- final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME);
+ final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME,
+ logSeparator);
assertEquals("Activity launched on secondary display must have proper configuration",
CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
}
@@ -379,6 +384,7 @@
* command and without specifying the display id - the second activity must appear on the
* primary display.
*/
+ @Presubmit
public void testConsequentLaunchActivity() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -411,6 +417,7 @@
* Tests launching an activity on virtual display and then launching another activity from the
* first one - it must appear on the secondary display, because it was launched from there.
*/
+ @Presubmit
public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -472,6 +479,7 @@
* Tests launching activities on secondary and then on primary display to see if the stack
* visibility is not affected.
*/
+ @Presubmit
public void testLaunchActivitiesAffectsVisibility() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -504,6 +512,7 @@
/**
* Test that move-task works when moving between displays.
*/
+ @Presubmit
public void testMoveTaskBetweenDisplays() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -534,6 +543,7 @@
* is moved correctly.
* This version launches virtual display creator to fullscreen stack.
*/
+ @Presubmit
public void testStackFocusSwitchOnDisplayRemoved() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -833,7 +843,7 @@
assertTrue("Focused stack must be on secondary display",
FULLSCREEN_WORKSPACE_STACK_ID != externalFocusedStackId);
- clearLogcat();
+ final String logSeparator = clearLogcat();
// Launch other activity with different uid and check it is launched on primary display.
final String broadcastAction = SECOND_PACKAGE_NAME + ".LAUNCH_BROADCAST_ACTION";
@@ -845,7 +855,7 @@
boolean match = false;
final Pattern pattern = Pattern.compile(".*SecurityException launching activity.*");
while (tries < 5 && !match) {
- String[] logs = getDeviceLogsForComponent("LaunchBroadcastReceiver");
+ String[] logs = getDeviceLogsForComponent("LaunchBroadcastReceiver", logSeparator);
for (String line : logs) {
Matcher m = pattern.matcher(line);
if (m.matches()) {
@@ -874,7 +884,7 @@
* Test that virtual display content is hidden when device is locked.
*/
public void testVirtualDisplayHidesContentWhenLocked() throws Exception {
- if (!supportsMultiDisplay()) { return; }
+ if (!supportsMultiDisplay() || !isHandheld()) { return; }
// Create new usual virtual display.
final DisplayState newDisplay = new VirtualDisplayBuilder(this).build();
@@ -896,54 +906,9 @@
}
/**
- * Test that show-with-insecure-keyguard virtual display is showing content when device is
- * locked.
- */
- public void testShowWhenLockedVirtualDisplay() throws Exception {
- if (!supportsMultiDisplay()) { return; }
-
- // Create new show-with-insecure-keyguard virtual display.
- final DisplayState newDisplay = new VirtualDisplayBuilder(this)
- .setCanShowWithInsecureKeyguard(true)
- .build();
- mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
-
- // Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
-
- // Lock the device.
- sleepDevice();
- mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_STOPPED);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
-
- // Unlock and check if visibility is back.
- wakeUpAndUnlockDevice();
- mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_RESUMED);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
- }
-
- /**
- * Test that only private virtual display can show content with insecure keyguard.
- */
- public void testShowWhenLockedPublicVirtualDisplay() throws Exception {
- if (!supportsMultiDisplay()) { return; }
-
- // Try to create new show-with-insecure-keyguard public virtual display.
- final DisplayState newDisplay = new VirtualDisplayBuilder(this)
- .setPublicDisplay(true)
- .setCanShowWithInsecureKeyguard(true)
- .setMustBeCreated(false)
- .build();
-
- // Check that the display is not created.
- mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
- assertNull(newDisplay);
- }
-
- /**
* Test that all activities that were on the private display are destroyed on display removal.
*/
+ @Presubmit
public void testContentDestroyOnDisplayRemoved() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -961,7 +926,7 @@
RESIZEABLE_ACTIVITY_NAME);
// Destroy the display and check if activities are removed from system.
- clearLogcat();
+ final String logSeparator = clearLogcat();
destroyVirtualDisplays();
final String activityName1
= ActivityManagerTestBase.getActivityComponentName(TEST_ACTIVITY_NAME);
@@ -991,13 +956,14 @@
assertFalse("Activity windows from removed display must be destroyed",
mAmWmState.getWmState().containsWindow(windowName2));
// Check activity logs.
- assertActivityDestroyed(TEST_ACTIVITY_NAME);
- assertActivityDestroyed(RESIZEABLE_ACTIVITY_NAME);
+ assertActivityDestroyed(TEST_ACTIVITY_NAME, logSeparator);
+ assertActivityDestroyed(RESIZEABLE_ACTIVITY_NAME, logSeparator);
}
/**
* Test that the update of display metrics updates all its content.
*/
+ @Presubmit
public void testDisplayResize() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -1012,22 +978,34 @@
mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
// Launch a resizeable activity on new secondary display.
- clearLogcat();
+ final String initialLogSeparator = clearLogcat();
launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId);
mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
mAmWmState.assertFocusedActivity("Launched activity must be focused",
RESIZEABLE_ACTIVITY_NAME);
// Grab reported sizes and compute new with slight size change.
- final ReportedSizes initialSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes initialSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME,
+ initialLogSeparator);
final Rectangle initialBounds
= mAmWmState.getAmState().getStackById(DOCKED_STACK_ID).getBounds();
final Rectangle newBounds = new Rectangle(initialBounds.x, initialBounds.y,
initialBounds.width + SIZE_VALUE_SHIFT, initialBounds.height + SIZE_VALUE_SHIFT);
// Resize the docked stack, so that activity with virtual display will also be resized.
- clearLogcat();
+ final String logSeparator = clearLogcat();
resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
+
+ mAmWmState.waitForWithAmState(mDevice, amState -> {
+ try {
+ return readConfigChangeNumber(RESIZEABLE_ACTIVITY_NAME, logSeparator) == 1
+ && amState.hasActivityState(RESIZEABLE_ACTIVITY_NAME, STATE_RESUMED);
+ } catch (Exception e) {
+ logE("Error waiting for valid state: " + e.getMessage());
+ return false;
+ }
+ }, "Wait for the configuration change to happen and for activity to be resumed.");
+
mAmWmState.computeState(mDevice, new String[] {RESIZEABLE_ACTIVITY_NAME, LAUNCHING_ACTIVITY,
VIRTUAL_DISPLAY_ACTIVITY}, false /* compareTaskAndStackBounds */);
mAmWmState.assertDockedTaskBounds(newBounds.width, newBounds.height,
@@ -1043,9 +1021,10 @@
// Check if activity in virtual display was resized properly.
assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY_NAME, 0 /* numRelaunch */,
- 1 /* numConfigChange */);
+ 1 /* numConfigChange */, logSeparator);
- final ReportedSizes updatedSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes updatedSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
assertTrue(updatedSize.widthDp <= initialSize.widthDp);
assertTrue(updatedSize.heightDp <= initialSize.heightDp);
assertTrue(updatedSize.displayWidth <= initialSize.displayWidth);
@@ -1056,10 +1035,16 @@
widthUpdated ^ heightUpdated);
}
+ /** Read the number of configuration changes sent to activity from logs. */
+ private int readConfigChangeNumber(String activityName, String logSeparator) throws Exception {
+ return (new ActivityLifecycleCounts(activityName, logSeparator)).mConfigurationChangedCount;
+ }
+
/**
* Tests that when activities that handle configuration changes are moved between displays,
* they receive onMovedToDisplay and onConfigurationChanged callbacks.
*/
+ @Presubmit
public void testOnMovedToDisplayCallback() throws Exception {
if (!supportsMultiDisplay()) { return; }
@@ -1072,7 +1057,7 @@
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
RESIZEABLE_ACTIVITY_NAME);
- clearLogcat();
+ final String logSeparator = clearLogcat();
moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.waitForFocusedStack(mDevice, FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertFocusedActivity("Focus must be on moved activity",
@@ -1081,8 +1066,8 @@
FULLSCREEN_WORKSPACE_STACK_ID);
// Check if client received the callbacks.
- assertMovedToDisplay(RESIZEABLE_ACTIVITY_NAME);
- assertMovedToDisplay("LifecycleLogView");
+ assertMovedToDisplay(RESIZEABLE_ACTIVITY_NAME, logSeparator);
+ assertMovedToDisplay("LifecycleLogView", logSeparator);
}
/**
@@ -1155,11 +1140,12 @@
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
// Launch activity on new secondary display.
+ String logSeparator = clearLogcat();
launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
RESIZEABLE_ACTIVITY_NAME);
final ReportedSizes initialSizes = getLastReportedSizesForActivity(
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY_NAME, logSeparator);
assertNotNull("Test activity must have reported initial sizes on launch", initialSizes);
// Rotate primary display and check that activity on secondary display is not affected.
@@ -1169,12 +1155,13 @@
final int initialRotation = mAmWmState.getWmState().getRotation();
setDeviceRotation((initialRotation + 1) % 4);
+ logSeparator = clearLogcat();
launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_RESUMED);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
TEST_ACTIVITY_NAME);
final ReportedSizes testActivitySizes = getLastReportedSizesForActivity(
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY_NAME, logSeparator);
assertEquals("Sizes of secondary display must not change after rotation of primary display",
initialSizes, testActivitySizes);
}
@@ -1251,7 +1238,7 @@
mAmWmState.waitForValidState(mDevice, new String[] {TEST_ACTIVITY_NAME},
null /* stackIds */, false /* compareTaskAndStackBounds */, componentName);
- // Check that the second activity is launched onto the fullscren stack
+ // Check that the second activity is launched onto the fullscreen stack
final ActivityManagerState.ActivityStack fullscreenStack =
mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID);
assertEquals("Activity launched on default display must be resumed",
@@ -1278,9 +1265,10 @@
private void rotateAndCheckSameSizes(String activityName) throws Exception {
for (int rotation = 3; rotation >= 0; --rotation) {
- clearLogcat();
+ final String logSeparator = clearLogcat();
setDeviceRotation(rotation);
- final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName);
+ final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName,
+ logSeparator);
assertNull("Sizes must not change after rotation", rotatedSizes);
}
}
@@ -1289,7 +1277,8 @@
* Test that display overrides apply correctly and won't be affected by display changes.
* This sets overrides to display size and density, initiates a display changed event by locking
* and unlocking the phone and verifies that overrides are kept.
- * */
+ */
+ @Presubmit
public void testForceDisplayMetrics() throws Exception {
launchHomeActivity();
@@ -1423,9 +1412,9 @@
}
/** Assert that component received onMovedToDisplay and onConfigurationChanged callbacks. */
- private void assertMovedToDisplay(String componentName) throws Exception {
+ private void assertMovedToDisplay(String componentName, String logSeparator) throws Exception {
final ActivityLifecycleCounts lifecycleCounts
- = new ActivityLifecycleCounts(componentName);
+ = new ActivityLifecycleCounts(componentName, logSeparator);
if (lifecycleCounts.mDestroyCount != 0) {
fail(componentName + " has been destroyed " + lifecycleCounts.mDestroyCount
+ " time(s), wasn't expecting any");
@@ -1462,8 +1451,6 @@
* @param densityDpi provide custom density for the display.
* @param launchInSplitScreen start {@link VirtualDisplayActivity} to side from
* {@link LaunchingActivity} on primary display.
- * @param canShowWithInsecureKeyguard allow showing content when device is showing an insecure
- * keyguard.
* @param publicDisplay make display public.
* @param mustBeCreated should assert if the display was or wasn't created.
* @param resizeDisplay should resize display when surface size changes.
@@ -1471,8 +1458,8 @@
* @throws Exception
*/
private List<DisplayState> createVirtualDisplays(int densityDpi, boolean launchInSplitScreen,
- boolean canShowWithInsecureKeyguard, boolean publicDisplay, boolean mustBeCreated,
- boolean resizeDisplay, int displayCount) throws Exception {
+ boolean publicDisplay, boolean mustBeCreated, boolean resizeDisplay, int displayCount)
+ throws Exception {
// Start an activity that is able to create virtual displays.
if (launchInSplitScreen) {
getLaunchActivityBuilder().setToSide(true)
@@ -1486,8 +1473,8 @@
final int originalDisplayCount = originalDS.mDisplayStates.size();
// Create virtual display with custom density dpi.
- executeShellCommand(getCreateVirtualDisplayCommand(densityDpi, canShowWithInsecureKeyguard,
- publicDisplay, resizeDisplay, displayCount));
+ executeShellCommand(getCreateVirtualDisplayCommand(densityDpi, publicDisplay, resizeDisplay,
+ displayCount));
mVirtualDisplayCreated = true;
// Wait for the virtual display to be created and get configurations.
@@ -1688,7 +1675,6 @@
private int mDensityDpi = CUSTOM_DENSITY_DPI;
private boolean mLaunchInSplitScreen = false;
- private boolean mCanShowWithInsecureKeyguard = false;
private boolean mPublicDisplay = false;
private boolean mMustBeCreated = true;
private boolean mResizeDisplay = true;
@@ -1707,12 +1693,6 @@
return this;
}
- public VirtualDisplayBuilder setCanShowWithInsecureKeyguard(
- boolean canShowWithInsecureKeyguard) {
- mCanShowWithInsecureKeyguard = canShowWithInsecureKeyguard;
- return this;
- }
-
public VirtualDisplayBuilder setPublicDisplay(boolean publicDisplay) {
mPublicDisplay = publicDisplay;
return this;
@@ -1733,15 +1713,13 @@
}
public List<DisplayState> build(int count) throws Exception {
- return mTests.createVirtualDisplays(mDensityDpi, mLaunchInSplitScreen,
- mCanShowWithInsecureKeyguard, mPublicDisplay, mMustBeCreated, mResizeDisplay,
- count);
+ return mTests.createVirtualDisplays(mDensityDpi, mLaunchInSplitScreen, mPublicDisplay,
+ mMustBeCreated, mResizeDisplay, count);
}
}
- private static String getCreateVirtualDisplayCommand(int densityDpi,
- boolean canShowWithInsecureKeyguard, boolean publicDisplay, boolean resizeDisplay,
- int displayCount) {
+ private static String getCreateVirtualDisplayCommand(int densityDpi, boolean publicDisplay,
+ boolean resizeDisplay, int displayCount) {
final StringBuilder commandBuilder
= new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
commandBuilder.append(" -f 0x20000000");
@@ -1750,8 +1728,6 @@
commandBuilder.append(" --ei density_dpi ").append(densityDpi);
}
commandBuilder.append(" --ei count ").append(displayCount);
- commandBuilder.append(" --ez can_show_with_insecure_keyguard ")
- .append(canShowWithInsecureKeyguard);
commandBuilder.append(" --ez public_display ").append(publicDisplay);
commandBuilder.append(" --ez resize_display ").append(resizeDisplay);
return commandBuilder.toString();
@@ -1764,15 +1740,6 @@
/** Checks if the device supports multi-display. */
private boolean supportsMultiDisplay() throws Exception {
- final String supportsMD = mDevice.executeShellCommand("am supports-multi-display").trim();
- if ("true".equals(supportsMD)) {
- return true;
- } else if ("false".equals(supportsMD)) {
- log("No Multi-Display support.");
- return false;
- } else {
- throw new Exception(
- "Device does not support \"am supports-multi-display\" shell command.");
- }
+ return hasDeviceFeature("android.software.activities_on_secondary_displays");
}
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index fb87ec2..d5ba74e 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -16,6 +16,9 @@
package android.server.cts;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.log.LogUtil.CLog;
+
import java.awt.Rectangle;
/**
@@ -36,6 +39,11 @@
private static final int STACK_SIZE = 300;
public void testStackList() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivity(TEST_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
@@ -45,6 +53,11 @@
}
public void testDockActivity() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(TEST_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
@@ -52,6 +65,11 @@
}
public void testNonResizeableNotDocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(NON_RESIZEABLE_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME});
@@ -62,6 +80,11 @@
}
public void testLaunchToSide() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
getLaunchActivityBuilder().setToSide(true).execute();
@@ -72,6 +95,11 @@
}
public void testLaunchToSideAndBringToFront() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME};
final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME};
@@ -107,6 +135,11 @@
}
public void testLaunchToSideMultiple() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
final String[] waitForActivitiesVisible =
@@ -148,6 +181,11 @@
private void launchTargetToSide(String targetActivityName,
boolean taskCountMustIncrement) throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
@@ -203,6 +241,11 @@
}
public void testLaunchToSideMultipleWithFlag() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
final String[] waitForActivitiesVisible =
@@ -232,6 +275,11 @@
}
public void testRotationWhenDocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
getLaunchActivityBuilder().setToSide(true).execute();
@@ -263,6 +311,11 @@
}
public void testRotationWhenDockedWhileLocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(LAUNCHING_ACTIVITY);
mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
getLaunchActivityBuilder().setToSide(true).execute();
@@ -283,6 +336,11 @@
}
public void testRotationWhileDockMinimized() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME);
assertDockMinimized();
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
@@ -314,6 +372,11 @@
}
public void testFinishDockActivityWhileMinimized() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStackAndMinimize(FINISHABLE_ACTIVITY_NAME);
assertDockMinimized();
@@ -324,6 +387,11 @@
}
public void testDockedStackToMinimizeWhenUnlocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(TEST_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
sleepDevice();
@@ -333,6 +401,11 @@
}
public void testMinimizedStateWhenUnlockedAndUnMinimized() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStackAndMinimize(FINISHABLE_ACTIVITY_NAME);
assertDockMinimized();
@@ -346,6 +419,11 @@
}
public void testResizeDockedStack() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
@@ -364,6 +442,11 @@
}
public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
final String[] waitTestActivityName = new String[] {TEST_ACTIVITY_NAME};
launchActivity(TEST_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, waitTestActivityName);
@@ -379,7 +462,7 @@
final Rectangle initialDockBounds =
mAmWmState.getWmState().getStack(DOCKED_STACK_ID).getBounds();
- clearLogcat();
+ final String logSeparator = clearLogcat();
Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
@@ -392,8 +475,8 @@
resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
mAmWmState.computeState(mDevice,
new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
- assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
- assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
+ assertActivityLifecycle(TEST_ACTIVITY_NAME, true /* relaunched */, logSeparator);
+ assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false /* relaunched */, logSeparator);
}
private Rectangle computeNewDockBounds(
@@ -414,6 +497,11 @@
}
public void testStackListOrderLaunchDockedActivity() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+ return;
+ }
+
launchActivityInDockStack(TEST_ACTIVITY_NAME);
mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY_NAME});
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
index cc36af1..df583d9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
@@ -101,14 +101,14 @@
mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
- clearLogcat();
+ final String logSeparator = clearLogcat();
resizeActivityTask(TEST_ACTIVITY,
TEST_TASK_OFFSET, TEST_TASK_OFFSET, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
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});
- assertActivityLifecycle(TEST_ACTIVITY, true);
- assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false);
+ assertActivityLifecycle(TEST_ACTIVITY, true /* relaunched */, logSeparator);
+ assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false /* relaunched */, logSeparator);
}
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
index b7df926..e6df4b2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
@@ -82,6 +82,10 @@
}
public void testMinimalSizeDocked() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+ return;
+ }
testMinimalSize(DOCKED_STACK_ID);
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index 9da97a2..a6372a2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -38,6 +38,7 @@
private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
private static final String RESUME_WHILE_PAUSING_ACTIVITY = "ResumeWhilePausingActivity";
private static final String PIP_ACTIVITY = "PipActivity";
+ private static final String PIP_ACTIVITY2 = "PipActivity2";
private static final String ALWAYS_FOCUSABLE_PIP_ACTIVITY = "AlwaysFocusablePipActivity";
private static final String LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY =
"LaunchIntoPinnedStackPipActivity";
@@ -467,6 +468,27 @@
ALWAYS_FOCUSABLE_PIP_ACTIVITY)));
}
+ public void testDisallowMultipleTasksInPinnedStack() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch first PIP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+
+ // Launch second PIP activity
+ launchActivity(PIP_ACTIVITY2, EXTRA_ENTER_PIP, "true");
+
+ final ActivityStack pinnedStack = mAmWmState.getAmState().getStackById(PINNED_STACK_ID);
+ assertEquals(1, pinnedStack.getTasks().size());
+
+ assertTrue(pinnedStack.getTasks().get(0).mRealActivity.equals(getActivityComponentName(
+ PIP_ACTIVITY2)));
+
+ final ActivityStack fullScreenStack = mAmWmState.getAmState().getStackById(
+ FULLSCREEN_WORKSPACE_STACK_ID);
+ assertTrue(fullScreenStack.getBottomTask().mRealActivity.equals(getActivityComponentName(
+ PIP_ACTIVITY)));
+ }
+
public void testPipUnPipOverHome() throws Exception {
if (!supportsPip()) return;
@@ -715,17 +737,17 @@
// Launch a PiP activity and ensure configuration change only happened once, and that the
// configuration change happened after the picture-in-picture and multi-window callbacks
launchActivity(PIP_ACTIVITY);
- clearLogcat();
+ String logSeparator = clearLogcat();
executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_ENTER_PIP);
mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, PINNED_STACK_ID);
assertPinnedStackExists();
- assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY);
+ assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY, logSeparator);
// Trigger it to go back to fullscreen and ensure that only triggered one configuration
// change as well
- clearLogcat();
+ logSeparator = clearLogcat();
launchActivity(PIP_ACTIVITY);
- assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY);
+ assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY, logSeparator);
}
public void testPreventSetAspectRatioWhileExpanding() throws Exception {
@@ -864,8 +886,10 @@
* Asserts that the activity received exactly one of each of the callbacks when entering and
* exiting picture-in-picture.
*/
- private void assertValidPictureInPictureCallbackOrder(String activityName) throws Exception {
- final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+ private void assertValidPictureInPictureCallbackOrder(String activityName, String logSeparator)
+ throws Exception {
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+ logSeparator);
if (lifecycleCounts.mConfigurationChangedCount != 1) {
fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
index 59d632a..3aa3ce0 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
@@ -49,6 +49,11 @@
}
private void testReplaceWindow_Dock(boolean relaunch) throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+ return;
+ }
+
final String activityName =
relaunch ? SLOW_CREATE_ACTIVITY_NAME : NO_RELAUNCH_ACTIVITY_NAME;
final String windowName = getWindowName(activityName);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
index 4afd607..a3099ae 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
@@ -45,6 +45,9 @@
}
public void testLockAndUnlock() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
gotoKeyguard();
mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
assertShowingAndNotOccluded();
@@ -54,6 +57,9 @@
}
public void testDismissKeyguard() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
gotoKeyguard();
mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
assertShowingAndNotOccluded();
@@ -65,6 +71,9 @@
}
public void testDismissKeyguard_whileOccluded() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
gotoKeyguard();
mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
assertShowingAndNotOccluded();
@@ -80,6 +89,9 @@
}
public void testDismissKeyguard_fromShowWhenLocked_notAllowed() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
gotoKeyguard();
mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
assertShowingAndNotOccluded();
@@ -98,7 +110,7 @@
if (!isHandheld()) {
return;
}
- clearLogcat();
+ final String logSeparator = clearLogcat();
gotoKeyguard();
mAmWmState.computeState(mDevice, null);
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -108,20 +120,20 @@
mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
- assertOnDismissSucceededInLogcat();
+ assertOnDismissSucceededInLogcat(logSeparator);
}
public void testDismissKeyguardActivity_method_cancelled() throws Exception {
if (!isHandheld()) {
return;
}
- clearLogcat();
+ final String logSeparator = clearLogcat();
gotoKeyguard();
mAmWmState.computeState(mDevice, null);
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
launchActivity("DismissKeyguardMethodActivity");
pressBackButton();
- assertOnDismissCancelledInLogcat();
+ assertOnDismissCancelledInLogcat(logSeparator);
mAmWmState.computeState(mDevice, new String[] {});
mAmWmState.assertVisibility("DismissKeyguardMethodActivity", false);
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
index ca86637..d578644 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
@@ -37,23 +37,24 @@
assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
}
- protected void assertOnDismissSucceededInLogcat() throws Exception {
- assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded");
+ protected void assertOnDismissSucceededInLogcat(String logSeparator) throws Exception {
+ assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded", logSeparator);
}
- protected void assertOnDismissCancelledInLogcat() throws Exception {
- assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled");
+ protected void assertOnDismissCancelledInLogcat(String logSeparator) throws Exception {
+ assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled", logSeparator);
}
- protected void assertOnDismissErrorInLogcat() throws Exception {
- assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError");
+ protected void assertOnDismissErrorInLogcat(String logSeparator) throws Exception {
+ assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError", logSeparator);
}
- private void assertInLogcat(String activityName, String entry) throws Exception {
+ private void assertInLogcat(String activityName, String entry, String logSeparator)
+ throws Exception {
final Pattern pattern = Pattern.compile("(.+)" + entry);
int tries = 0;
while (tries < 5) {
- final String[] lines = getDeviceLogsForComponent(activityName);
+ final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
log("Looking at logcat");
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
index fa611ad..877369a 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
@@ -174,7 +174,7 @@
if (!isHandheld()) {
return;
}
- clearLogcat();
+ final String logSeparator = clearLogcat();
gotoKeyguard();
mAmWmState.computeState(mDevice, null);
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -183,28 +183,28 @@
mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
- assertOnDismissSucceededInLogcat();
+ assertOnDismissSucceededInLogcat(logSeparator);
}
public void testDismissKeyguardActivity_method_notTop() throws Exception {
if (!isHandheld()) {
return;
}
- clearLogcat();
+ final String logSeparator = clearLogcat();
gotoKeyguard();
mAmWmState.computeState(mDevice, null);
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
launchActivity("BroadcastReceiverActivity");
launchActivity("TestActivity");
executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguardMethod true");
- assertOnDismissErrorInLogcat();
+ assertOnDismissErrorInLogcat(logSeparator);
}
public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
if (!isHandheld()) {
return;
}
- clearLogcat();
+ final String logSeparator = clearLogcat();
sleepDevice();
mAmWmState.computeState(mDevice, null);
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -213,10 +213,13 @@
mAmWmState.computeState(mDevice, new String[] { "TurnScreenOnDismissKeyguardActivity"});
mAmWmState.assertVisibility("TurnScreenOnDismissKeyguardActivity", true);
assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
- assertOnDismissSucceededInLogcat();
+ assertOnDismissSucceededInLogcat(logSeparator);
}
public void testDismissKeyguard_fromShowWhenLocked_notAllowed() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
gotoKeyguard();
mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
assertShowingAndNotOccluded();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/SplashscreenTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/SplashscreenTests.java
new file mode 100644
index 0000000..4694d7a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/SplashscreenTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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.cts;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.SplashscreenTests
+ */
+public class SplashscreenTests extends ActivityManagerTestBase {
+
+ public void testSplashscreenContent() throws Exception {
+ launchActivityNoWait("SplashscreenActivity");
+ mAmWmState.waitForAppTransitionIdle(mDevice);
+ mAmWmState.getWmState().getStableBounds();
+ final BufferedImage image = takeScreenshot();
+ assertAllColor(image, mAmWmState.getWmState().getStableBounds(), Color.RED.getRGB());
+ }
+
+ private void assertAllColor(BufferedImage img, Rectangle bounds, int expectedColor) {
+ for (int x = bounds.x; x < bounds.x + bounds.width; x++) {
+ for (int y = bounds.y; y < bounds.y + bounds.height; y++) {
+ assertTrue(x < img.getWidth());
+ assertTrue(y < img.getHeight());
+ final int color = img.getRGB(x, y);
+ assertEquals("Colors must match at x=" + x + " y=" + y, expectedColor, color);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
index ece45f2..9f4cf6c 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -34,13 +34,12 @@
import junit.framework.Assert;
-import java.awt.*;
+import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
-import java.util.regex.Pattern;
/** Combined state of the activity manager and window manager. */
public class ActivityAndWindowManagersState extends Assert {
@@ -195,7 +194,8 @@
mAmState.computeState(device);
mWmState.computeState(device);
if (shouldWaitForValidStacks(compareTaskAndStackBounds)
- || shouldWaitForActivities(waitForActivitiesVisible, stackIds, packageName)) {
+ || shouldWaitForActivities(waitForActivitiesVisible, stackIds, packageName)
+ || shouldWaitForWindows()) {
log("***Waiting for valid stacks and activities states...");
try {
Thread.sleep(1000);
@@ -252,6 +252,12 @@
"***Waiting for focused stack...");
}
+ void waitForAppTransitionIdle(ITestDevice device) throws Exception {
+ waitForWithWmState(device,
+ state -> WindowManagerState.APP_STATE_IDLE.equals(state.getAppTransitionState()),
+ "***Waiting for app transition idle...");
+ }
+
void waitForWithAmState(ITestDevice device, Predicate<ActivityManagerState> waitCondition,
String message) throws Exception{
waitFor(device, (amState, wmState) -> waitCondition.test(amState), message);
@@ -283,6 +289,7 @@
} while (retriesLeft-- > 0);
}
+ /** @return true if should wait for valid stacks state. */
private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
if (!taskListsInAmAndWmAreEqual()) {
// We want to wait for equal task lists in AM and WM in case we caught them in the
@@ -304,9 +311,24 @@
log("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
return true;
}
+ final int stackCount = mAmState.getStackCount();
+ if (stackCount == 0) {
+ log("***stackCount=" + stackCount);
+ return true;
+ }
+ final int resumedActivitiesCount = mAmState.getResumedActivitiesCount();
+ if (!mAmState.getKeyguardControllerState().keyguardShowing && resumedActivitiesCount != 1) {
+ log("***resumedActivitiesCount=" + resumedActivitiesCount);
+ return true;
+ }
+ if (mAmState.getFocusedActivity() == null) {
+ log("***focusedActivity=null");
+ return true;
+ }
return false;
}
+ /** @return true if should wait for some activities to become visible. */
private boolean shouldWaitForActivities(String[] waitForActivitiesVisible, int[] stackIds,
String packageName) {
if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
@@ -353,6 +375,24 @@
return !allActivityWindowsVisible || !tasksInCorrectStacks;
}
+ /** @return true if should wait valid windows state. */
+ private boolean shouldWaitForWindows() {
+ if (mWmState.getFrontWindow() == null) {
+ log("***frontWindow=null");
+ return true;
+ }
+ if (mWmState.getFocusedWindow() == null) {
+ log("***focusedWindow=null");
+ return true;
+ }
+ if (mWmState.getFocusedApp() == null) {
+ log("***focusedApp=null");
+ return true;
+ }
+
+ return false;
+ }
+
private boolean shouldWaitForDebuggerWindow() {
List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
mWmState.getMatchingVisibleWindowState("android.server.cts", matchingWindowStates);
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 4f9c3ac..4ef07cf 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -21,13 +21,17 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.testtype.DeviceTestCase;
+import java.awt.*;
+import java.awt.image.BufferedImage;
import java.lang.Exception;
import java.lang.Integer;
import java.lang.String;
import java.util.HashSet;
import java.util.List;
+import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -36,9 +40,12 @@
import android.server.cts.ActivityManagerState.ActivityStack;
+import javax.imageio.ImageIO;
+
public abstract class ActivityManagerTestBase extends DeviceTestCase {
private static final boolean PRETEND_DEVICE_SUPPORTS_PIP = false;
private static final boolean PRETEND_DEVICE_SUPPORTS_FREEFORM = false;
+ private static final String LOG_SEPARATOR = "LOG_SEPARATOR";
// Constants copied from ActivityManager.StackId. If they are changed there, these must be
// updated.
@@ -113,6 +120,10 @@
static final String AM_MOVE_TASK = "am stack move-task ";
+ private static final String AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW =
+ "am supports-split-screen-multiwindow";
+ private static final String AM_NO_HOME_SCREEN = "am no-home-screen";
+
private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
private static final String INPUT_KEYEVENT_BACK = "input keyevent 4";
private static final String INPUT_KEYEVENT_APP_SWITCH = "input keyevent 187";
@@ -285,13 +296,25 @@
mDevice.executeShellCommand(command, outputReceiver);
}
+ protected BufferedImage takeScreenshot() throws Exception {
+ final InputStreamSource stream = mDevice.getScreenshot("PNG", false /* rescale */);
+ if (stream == null) {
+ fail("Failed to take screenshot of device");
+ }
+ return ImageIO.read(stream.createInputStream());
+ }
+
protected void launchActivity(final String targetActivityName, final String... keyValuePairs)
throws Exception {
executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
-
mAmWmState.waitForValidState(mDevice, targetActivityName);
}
+ protected void launchActivityNoWait(final String targetActivityName,
+ final String... keyValuePairs) throws Exception {
+ executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
+ }
+
protected void launchActivityInNewTask(final String targetActivityName) throws Exception {
executeShellCommand(getAmStartCmdInNewTask(targetActivityName));
mAmWmState.waitForValidState(mDevice, targetActivityName);
@@ -502,6 +525,20 @@
&& !hasDeviceFeature("android.software.watch");
}
+ protected boolean supportsSplitScreenMultiWindow() throws DeviceNotAvailableException {
+ CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ executeShellCommand(AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW, outputReceiver);
+ String output = outputReceiver.getOutput();
+ return !output.startsWith("false");
+ }
+
+ protected boolean noHomeScreen() throws DeviceNotAvailableException {
+ CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ executeShellCommand(AM_NO_HOME_SCREEN, outputReceiver);
+ String output = outputReceiver.getOutput();
+ return output.startsWith("true");
+ }
+
protected boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
if (mAvailableFeatures == null) {
// TODO: Move this logic to ITestDevice.
@@ -687,86 +724,184 @@
return output;
}
- protected void clearLogcat() throws DeviceNotAvailableException {
+ /**
+ * Tries to clear logcat and inserts log separator in case clearing didn't succeed, so we can
+ * always find the starting point from where to evaluate following logs.
+ * @return Unique log separator.
+ */
+ protected String clearLogcat() throws DeviceNotAvailableException {
mDevice.executeAdbCommand("logcat", "-c");
+ final String uniqueString = UUID.randomUUID().toString();
+ executeShellCommand("log -t " + LOG_SEPARATOR + " " + uniqueString);
+ return uniqueString;
}
- protected void assertActivityLifecycle(String activityName, boolean relaunched)
- throws DeviceNotAvailableException {
- final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+ void assertActivityLifecycle(String activityName, boolean relaunched,
+ String logSeparator) throws DeviceNotAvailableException {
+ int retriesLeft = 5;
+ String resultString;
+ do {
+ resultString = verifyLifecycleCondition(activityName, logSeparator, relaunched);
+ if (resultString != null) {
+ log("***Waiting for valid lifecycle state: " + resultString);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ log(e.toString());
+ }
+ } else {
+ break;
+ }
+ } while (retriesLeft-- > 0);
+ assertNull(resultString, resultString);
+ }
+
+ /** @return Error string if lifecycle counts don't match, null if everything is fine. */
+ private String verifyLifecycleCondition(String activityName, String logSeparator,
+ boolean relaunched) throws DeviceNotAvailableException {
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+ logSeparator);
if (relaunched) {
if (lifecycleCounts.mDestroyCount < 1) {
- fail(activityName + " must have been destroyed. mDestroyCount="
- + lifecycleCounts.mDestroyCount);
+ return activityName + " must have been destroyed. mDestroyCount="
+ + lifecycleCounts.mDestroyCount;
}
if (lifecycleCounts.mCreateCount < 1) {
- fail(activityName + " must have been (re)created. mCreateCount="
- + lifecycleCounts.mCreateCount);
+ return activityName + " must have been (re)created. mCreateCount="
+ + lifecycleCounts.mCreateCount;
}
} else {
if (lifecycleCounts.mDestroyCount > 0) {
- fail(activityName + " must *NOT* have been destroyed. mDestroyCount="
- + lifecycleCounts.mDestroyCount);
+ return activityName + " must *NOT* have been destroyed. mDestroyCount="
+ + lifecycleCounts.mDestroyCount;
}
if (lifecycleCounts.mCreateCount > 0) {
- fail(activityName + " must *NOT* have been (re)created. mCreateCount="
- + lifecycleCounts.mCreateCount);
+ return activityName + " must *NOT* have been (re)created. mCreateCount="
+ + lifecycleCounts.mCreateCount;
}
if (lifecycleCounts.mConfigurationChangedCount < 1) {
- fail(activityName + " must have received configuration changed. "
+ return activityName + " must have received configuration changed. "
+ "mConfigurationChangedCount="
- + lifecycleCounts.mConfigurationChangedCount);
+ + lifecycleCounts.mConfigurationChangedCount;
}
}
+ return null;
}
protected void assertRelaunchOrConfigChanged(
- String activityName, int numRelaunch, int numConfigChange)
+ String activityName, int numRelaunch, int numConfigChange, String logSeparator)
throws DeviceNotAvailableException {
- final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+ int retriesLeft = 5;
+ String resultString;
+ do {
+ resultString = verifyRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange,
+ logSeparator);
+ if (resultString != null) {
+ log("***Waiting for relaunch or config changed: " + resultString);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ log(e.toString());
+ }
+ } else {
+ break;
+ }
+ } while (retriesLeft-- > 0);
+
+ assertNull(resultString, resultString);
+ }
+
+ /** @return Error string if lifecycle counts don't match, null if everything is fine. */
+ private String verifyRelaunchOrConfigChanged(String activityName, int numRelaunch,
+ int numConfigChange, String logSeparator) throws DeviceNotAvailableException {
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+ logSeparator);
if (lifecycleCounts.mDestroyCount != numRelaunch) {
- fail(activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
- + " time(s), expecting " + numRelaunch);
+ return activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+ + " time(s), expecting " + numRelaunch;
} else if (lifecycleCounts.mCreateCount != numRelaunch) {
- fail(activityName + " has been (re)created " + lifecycleCounts.mCreateCount
- + " time(s), expecting " + numRelaunch);
+ return activityName + " has been (re)created " + lifecycleCounts.mCreateCount
+ + " time(s), expecting " + numRelaunch;
} else if (lifecycleCounts.mConfigurationChangedCount != numConfigChange) {
- fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
- + " onConfigurationChanged() calls, expecting " + numConfigChange);
+ return activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
+ + " onConfigurationChanged() calls, expecting " + numConfigChange;
}
+ return null;
}
- protected void assertActivityDestroyed(String activityName) throws DeviceNotAvailableException {
- final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+ protected void assertActivityDestroyed(String activityName, String logSeparator)
+ throws DeviceNotAvailableException {
+ int retriesLeft = 5;
+ String resultString;
+ do {
+ resultString = verifyActivityDestroyed(activityName, logSeparator);
+ if (resultString != null) {
+ log("***Waiting for activity destroyed: " + resultString);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ log(e.toString());
+ }
+ } else {
+ break;
+ }
+ } while (retriesLeft-- > 0);
+
+ assertNull(resultString, resultString);
+ }
+
+ /** @return Error string if lifecycle counts don't match, null if everything is fine. */
+ private String verifyActivityDestroyed(String activityName, String logSeparator)
+ throws DeviceNotAvailableException {
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+ logSeparator);
if (lifecycleCounts.mDestroyCount != 1) {
- fail(activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
- + " time(s), expecting single destruction.");
+ return activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+ + " time(s), expecting single destruction.";
} else if (lifecycleCounts.mCreateCount != 0) {
- fail(activityName + " has been (re)created " + lifecycleCounts.mCreateCount
- + " time(s), not expecting any.");
+ return activityName + " has been (re)created " + lifecycleCounts.mCreateCount
+ + " time(s), not expecting any.";
} else if (lifecycleCounts.mConfigurationChangedCount != 0) {
- fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
- + " onConfigurationChanged() calls, not expecting any.");
+ return activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
+ + " onConfigurationChanged() calls, not expecting any.";
}
+ return null;
}
- protected String[] getDeviceLogsForComponent(String componentName)
+ protected String[] getDeviceLogsForComponent(String componentName, String logSeparator)
throws DeviceNotAvailableException {
- return mDevice.executeAdbCommand(
- "logcat", "-v", "brief", "-d", componentName + ":I", "*:S").split("\\n");
+ return getDeviceLogsForComponents(new String[]{componentName}, logSeparator);
}
- protected String[] getDeviceLogsForComponents(final String[] componentNames)
- throws DeviceNotAvailableException {
- String filters = "";
- for (int i = 0; i < componentNames.length; i++) {
- filters += componentNames[i] + ":I ";
+ protected String[] getDeviceLogsForComponents(final String[] componentNames,
+ String logSeparator) throws DeviceNotAvailableException {
+ String filters = LOG_SEPARATOR + ":I ";
+ for (String component : componentNames) {
+ filters += component + ":I ";
}
- return mDevice.executeAdbCommand(
+ final String[] result = mDevice.executeAdbCommand(
"logcat", "-v", "brief", "-d", filters, "*:S").split("\\n");
+ if (logSeparator == null) {
+ return result;
+ }
+
+ // Make sure that we only check logs after the separator.
+ int i = 0;
+ boolean lookingForSeparator = true;
+ while (i < result.length && lookingForSeparator) {
+ if (result[i].contains(logSeparator)) {
+ lookingForSeparator = false;
+ }
+ i++;
+ }
+ final String[] filteredResult = new String[result.length - i];
+ for (int curPos = 0; i < result.length; curPos++, i++) {
+ filteredResult[curPos] = result[i];
+ }
+ return filteredResult;
}
private static final Pattern sCreatePattern = Pattern.compile("(.+): onCreate");
@@ -819,9 +954,30 @@
}
}
- ReportedSizes getLastReportedSizesForActivity(String activityName)
+ ReportedSizes getLastReportedSizesForActivity(String activityName, String logSeparator)
throws DeviceNotAvailableException {
- final String[] lines = getDeviceLogsForComponent(activityName);
+ int retriesLeft = 5;
+ ReportedSizes result;
+ do {
+ result = readLastReportedSizes(activityName, logSeparator);
+ if (result == null) {
+ log("***Waiting for sizes to be reported...");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ log(e.toString());
+ // Well I guess we are not waiting...
+ }
+ } else {
+ break;
+ }
+ } while (retriesLeft-- > 0);
+ return result;
+ }
+
+ private ReportedSizes readLastReportedSizes(String activityName, String logSeparator)
+ throws DeviceNotAvailableException {
+ final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
final Matcher matcher = sNewConfigPattern.matcher(line);
@@ -852,9 +1008,10 @@
int mLastPictureInPictureModeChangedLineIndex;
int mDestroyCount;
- public ActivityLifecycleCounts(String activityName) throws DeviceNotAvailableException {
+ public ActivityLifecycleCounts(String activityName, String logSeparator)
+ throws DeviceNotAvailableException {
int lineIndex = 0;
- for (String line : getDeviceLogsForComponent(activityName)) {
+ for (String line : getDeviceLogsForComponent(activityName, logSeparator)) {
line = line.trim();
lineIndex++;
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index f9ad434..0cdf13e 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -37,7 +37,7 @@
public class WindowManagerState {
- public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
+ public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE";
public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN";
public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE";
@@ -53,6 +53,8 @@
public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE";
public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE";
+ public static final String APP_STATE_IDLE = "APP_STATE_IDLE";
+
private static final String DUMPSYS_WINDOW = "dumpsys window -a";
private static final Pattern sWindowPattern =
@@ -87,6 +89,8 @@
private static final Pattern sLastAppTransitionPattern =
Pattern.compile("mLastUsedAppTransition=(.+)");
+ private static final Pattern sAppTransitionStatePattern =
+ Pattern.compile("mAppTransitionState=(.+)");
private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)");
@@ -120,6 +124,7 @@
private String mFocusedWindow = null;
private String mFocusedApp = null;
private String mLastTransition = null;
+ private String mAppTransitionState = null;
private String mInputMethodWindowAppToken = null;
private Rectangle mStableBounds = new Rectangle();
private final Rectangle mDefaultPinnedStackBounds = new Rectangle();
@@ -157,7 +162,7 @@
dump = outputReceiver.getOutput();
parseSysDump(dump);
- retry = mWindowStates.isEmpty() || mFocusedWindow == null || mFocusedApp == null;
+ retry = mWindowStates.isEmpty() || mFocusedApp == null;
} while (retry && retriesLeft-- > 0);
if (retry) {
@@ -260,6 +265,15 @@
continue;
}
+ matcher = sAppTransitionStatePattern.matcher(line);
+ if (matcher.matches()) {
+ log(line);
+ final String appTransitionState = matcher.group(1);
+ log(appTransitionState);
+ mAppTransitionState = appTransitionState;
+ continue;
+ }
+
matcher = sLastAppTransitionPattern.matcher(line);
if (matcher.matches()) {
log(line);
@@ -442,6 +456,10 @@
return mLastTransition;
}
+ String getAppTransitionState() {
+ return mAppTransitionState;
+ }
+
int getFrontStackId(int displayId) {
return mDisplayStacks.get(displayId).get(0).mStackId;
}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
index f594123..6281e16 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
@@ -24,6 +24,7 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.regex.Pattern;
public class CrossAppDragAndDropTests extends DeviceTestCase {
// Constants copied from ActivityManager.StackId. If they are changed there, these must be
@@ -42,12 +43,18 @@
private static final String AM_FORCE_STOP = "am force-stop ";
private static final String AM_MOVE_TASK = "am stack move-task ";
+ private static final String AM_RESIZE_TASK = "am task resize ";
private static final String AM_REMOVE_STACK = "am stack remove ";
private static final String AM_START_N = "am start -n ";
private static final String AM_STACK_LIST = "am stack list";
private static final String INPUT_MOUSE_SWIPE = "input mouse swipe ";
private static final String TASK_ID_PREFIX = "taskId";
+ // Regex pattern to match adb shell am stack list output of the form:
+ // taskId=<TASK_ID>: <componentName> bounds=[LEFT,TOP][RIGHT,BOTTOM]
+ private static final String TASK_REGEX_PATTERN_STRING =
+ "taskId=[0-9]+: %s bounds=\\[[0-9]+,[0-9]+\\]\\[[0-9]+,[0-9]+\\]";
+
private static final int SWIPE_DURATION_MS = 500;
private static final String SOURCE_PACKAGE_NAME = "android.wm.cts.dndsourceapp";
@@ -94,6 +101,9 @@
private static final String RESULT_EXCEPTION = "Exception";
private static final String RESULT_NULL_DROP_PERMISSIONS = "Null DragAndDropPermissions";
+ private static final String AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW =
+ "am supports-split-screen-multiwindow";
+
private ITestDevice mDevice;
private Map<String, String> mSourceResults;
@@ -145,6 +155,12 @@
return AM_MOVE_TASK + taskId + " " + stackId + " true";
}
+ private String getResizeTaskCommand(int taskId, Point topLeft, Point bottomRight)
+ throws Exception {
+ return AM_RESIZE_TASK + taskId + " " + topLeft.x + " " + topLeft.y + " " + bottomRight.x
+ + " " + bottomRight.y;
+ }
+
private String getComponentName(String packageName, String activityName) {
return packageName + "/" + packageName + "." + activityName;
}
@@ -195,6 +211,24 @@
waitForResume(packageName, activityName);
}
+ /**
+ * @param displaySize size of the display
+ * @param leftSide {@code true} to launch the app taking up the left half of the display,
+ * {@code false} to launch the app taking up the right half of the display.
+ */
+ private void launchFreeformActivity(String packageName, String activityName, String mode,
+ Point displaySize, boolean leftSide) throws Exception{
+ clearLogs();
+ final String componentName = getComponentName(packageName, activityName);
+ executeShellCommand(getStartCommand(componentName, mode) + " --stack "
+ + FREEFORM_WORKSPACE_STACK_ID);
+ waitForResume(packageName, activityName);
+ Point topLeft = new Point(leftSide ? 0 : displaySize.x / 2, 0);
+ Point bottomRight = new Point(leftSide ? displaySize.x / 2 : displaySize.x, displaySize.y);
+ executeShellCommand(getResizeTaskCommand(getActivityTaskId(componentName), topLeft,
+ bottomRight));
+ }
+
private void waitForResume(String packageName, String activityName) throws Exception {
final String fullActivityName = packageName + "." + activityName;
int retryCount = 3;
@@ -238,6 +272,7 @@
builder.append("\nParsing adb shell am output: " );
builder.append(output);
CLog.i(builder.toString());
+ final Pattern pattern = Pattern.compile(String.format(TASK_REGEX_PATTERN_STRING, name));
for (String line : output.split("\\n")) {
final String truncatedLine;
// Only look for the activity name before the "topActivity" string.
@@ -247,7 +282,7 @@
} else {
truncatedLine = line;
}
- if (truncatedLine.contains(name)) {
+ if (pattern.matcher(truncatedLine).find()) {
return truncatedLine;
}
}
@@ -280,6 +315,12 @@
return -1;
}
+ private Point getDisplaySize() throws Exception {
+ final String output = executeShellCommand("wm size");
+ final String[] sizes = output.split(" ")[2].split("x");
+ return new Point(Integer.valueOf(sizes[0].trim()), Integer.valueOf(sizes[1].trim()));
+ }
+
private Point getWindowCenter(String name) throws Exception {
Point p1 = new Point();
Point p2 = new Point();
@@ -343,8 +384,19 @@
return;
}
- launchDockedActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode);
- launchFullscreenActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode);
+ if (supportsSplitScreenMultiWindow()) {
+ launchDockedActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode);
+ launchFullscreenActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode);
+ } else if (supportsFreeformMultiWindow()) {
+ // Fallback to try to launch two freeform windows side by side.
+ Point displaySize = getDisplaySize();
+ launchFreeformActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode,
+ displaySize, true /* leftSide */);
+ launchFreeformActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode,
+ displaySize, false /* leftSide */);
+ } else {
+ return;
+ }
clearLogs();
@@ -412,6 +464,14 @@
}
}
+ private boolean supportsSplitScreenMultiWindow() throws DeviceNotAvailableException {
+ return !executeShellCommand(AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW).startsWith("false");
+ }
+
+ private boolean supportsFreeformMultiWindow() throws DeviceNotAvailableException {
+ return mDevice.hasFeature("feature:android.software.freeform_window_management");
+ }
+
public void testCancelSoon() throws Exception {
assertDropResult(CANCEL_SOON, REQUEST_NONE, RESULT_MISSING);
}
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
index 595ee74..d3118ad 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
@@ -19,6 +19,8 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
+import java.util.concurrent.TimeUnit;
+
public class ShortcutManagerBackupTest extends BaseShortcutManagerHostTest {
private static final String LAUNCHER1_APK = "CtsShortcutBackupLauncher1.apk";
private static final String LAUNCHER2_APK = "CtsShortcutBackupLauncher2.apk";
@@ -40,6 +42,8 @@
private static final String PUBLISHER3_PKG =
"android.content.pm.cts.shortcut.backup.publisher3";
+ private static final int BROADCAST_TIMEOUT_SECONDS = 120;
+
private static final String FEATURE_BACKUP = "android.software.backup";
private boolean mSupportsBackup;
@@ -57,6 +61,16 @@
clearShortcuts(PUBLISHER1_PKG, getPrimaryUserId());
clearShortcuts(PUBLISHER2_PKG, getPrimaryUserId());
clearShortcuts(PUBLISHER3_PKG, getPrimaryUserId());
+
+ getDevice().uninstallPackage(LAUNCHER1_PKG);
+ getDevice().uninstallPackage(LAUNCHER2_PKG);
+ getDevice().uninstallPackage(LAUNCHER3_PKG);
+
+ getDevice().uninstallPackage(PUBLISHER1_PKG);
+ getDevice().uninstallPackage(PUBLISHER2_PKG);
+ getDevice().uninstallPackage(PUBLISHER3_PKG);
+
+ waitUntilPackagesGone();
}
}
@@ -106,10 +120,46 @@
}
+ /**
+ * Wait until all the test packages are forgotten by the shortcut manager.
+ */
+ private void waitUntilPackagesGone() throws Exception {
+ CLog.i("Waiting until all packages are removed from shortcut manager...");
+
+ final String packages[] = {
+ LAUNCHER1_PKG, LAUNCHER2_PKG, LAUNCHER3_PKG,
+ PUBLISHER1_PKG, PUBLISHER2_PKG, PUBLISHER3_PKG,
+ };
+
+ String dumpsys = "";
+ final long TIMEOUT = System.nanoTime() +
+ TimeUnit.SECONDS.toNanos(BROADCAST_TIMEOUT_SECONDS);
+
+ while (System.nanoTime() < TIMEOUT) {
+ Thread.sleep(2000);
+ dumpsys = getDevice().executeShellCommand("dumpsys shortcut");
+
+ if (dumpsys.contains("Launcher: " + LAUNCHER1_PKG)) continue;
+ if (dumpsys.contains("Launcher: " + LAUNCHER2_PKG)) continue;
+ if (dumpsys.contains("Launcher: " + LAUNCHER3_PKG)) continue;
+ if (dumpsys.contains("Package: " + PUBLISHER1_PKG)) continue;
+ if (dumpsys.contains("Package: " + PUBLISHER2_PKG)) continue;
+ if (dumpsys.contains("Package: " + PUBLISHER3_PKG)) continue;
+
+ dumpsys("All clear");
+
+ // All packages gone.
+ return;
+ }
+ fail("ShortcutManager didn't handle all expected broadcasts before time out."
+ + " Last dumpsys=\n" + dumpsys);
+ }
+
public void testBackupAndRestore() throws Exception {
if (!mSupportsBackup) {
return;
}
+ dumpsys("Test start");
installAppAsUser(LAUNCHER1_APK, getPrimaryUserId());
installAppAsUser(LAUNCHER2_APK, getPrimaryUserId());
@@ -131,6 +181,8 @@
// Tweak shortcuts a little bit to make disabled shortcuts.
runDeviceTestsAsUser(PUBLISHER2_PKG, ".ShortcutManagerPreBackup2Test", getPrimaryUserId());
+ dumpsys("Before backup");
+
// Backup
doBackup();
@@ -143,9 +195,14 @@
getDevice().uninstallPackage(PUBLISHER2_PKG);
getDevice().uninstallPackage(PUBLISHER3_PKG);
+ // Make sure the shortcut service handled all the uninstall broadcasts.
+ waitUntilPackagesGone();
+
// Then restore
doRestore();
+ dumpsys("After restore");
+
// First, restore launcher 1, which shouldn't see any shortcuts from the packages yet.
installAppAsUser(LAUNCHER1_APK, getPrimaryUserId());
runDeviceTestsAsUser(LAUNCHER1_PKG, ".ShortcutManagerPostBackupTest",
diff --git a/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java b/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java
index d599546..a8871a3 100644
--- a/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java
+++ b/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java
@@ -99,6 +99,8 @@
getDevice().executeShellCommand(SLEEP_COMMAND);
// Start the APK and wait for it to complete.
getDevice().executeShellCommand(START_COMMAND);
+ // Give the activity some time to start
+ Thread.sleep(500);
// Dump logcat.
String logs = getDevice().executeAdbCommand(
"logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
diff --git a/hostsidetests/webkit/AndroidTest.xml b/hostsidetests/webkit/AndroidTest.xml
index 8641395..5a0eeca 100644
--- a/hostsidetests/webkit/AndroidTest.xml
+++ b/hostsidetests/webkit/AndroidTest.xml
@@ -17,7 +17,6 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsWebViewStartupApp.apk" />
- <option name="test-file-name" value="CtsWebViewRendererCrash.apk" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/webkit/renderprocesscrash/AndroidManifest.xml b/hostsidetests/webkit/renderprocesscrash/AndroidManifest.xml
deleted file mode 100644
index d1744e5..0000000
--- a/hostsidetests/webkit/renderprocesscrash/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.webkit.renderprocesscrash">
-
- <uses-permission android:name="android.permission.INTERNET" />
-
- <application android:maxRecents="1">
- <activity android:name=".RenderProcessCrashActivity"
- android:label="RenderProcessCrashActivity"
- android:screenOrientation="nosensor">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/hostsidetests/webkit/src/com/android/cts/webkit/RenderProcessCrashTest.java b/hostsidetests/webkit/src/com/android/cts/webkit/RenderProcessCrashTest.java
deleted file mode 100644
index 2f65afc..0000000
--- a/hostsidetests/webkit/src/com/android/cts/webkit/RenderProcessCrashTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 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.webkit;
-
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.TestDeviceOptions;
-import com.android.tradefed.testtype.DeviceTestCase;
-
-import java.util.Scanner;
-
-/**
- * This test lanuches RenderProcessCrashActivity which crashes render process, and
- * checks specific crash log in Logcat to verify Render process crashed.
- */
-public class RenderProcessCrashTest extends DeviceTestCase {
- /**
- * The package name of the APK.
- */
- private static final String PACKAGE = "com.android.cts.webkit.renderprocesscrash";
-
- /**
- * The class name of the main activity in the APK.
- */
- private static final String CLASS = "RenderProcessCrashActivity";
-
- /**
- * The command to launch the main activity.
- */
- private static final String START_COMMAND = String.format(
- "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
-
- /**
- * The test string to look for.
- */
- private static final String TEST_STRING = "kill (OOM or update) wasn't handed by all associated"
- + " webviews, killing application.";
-
- /**
- * Tests the string was successfully logged to Logcat from the activity.
- *
- * @throws Exception
- */
- public void testCrash() throws Exception {
- ITestDevice device = getDevice();
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- TestDeviceOptions options = new TestDeviceOptions();
- options.setLogcatOptions("-v brief -d chromium:E *:S");
- device.setOptions(options);
-
- // Start the APK.
- device.executeShellCommand(START_COMMAND);
- // Dump logcat.
- device.startLogcat();
- // Search for string.
- Scanner in = new Scanner(device.getLogcat().createInputStream());
- boolean found = false;
- int tryTimes = 10;
- while (tryTimes-- > 0) {
- while (in.hasNextLine()) {
- String line = in.nextLine().trim();
- if(line.endsWith(TEST_STRING)) {
- found = true;
- break;
- }
- }
- if (found) break;
- Thread.sleep(1000);
- }
- in.close();
- device.stopLogcat();
- assertTrue("Can't not find crash log " + TEST_STRING, found);
- }
-}
diff --git a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
index e914ee2..1955483 100644
--- a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
+++ b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
@@ -17,14 +17,22 @@
package android.jobscheduler;
import android.annotation.TargetApi;
+import android.app.job.JobInfo;
import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.app.job.JobWorkItem;
import android.content.ClipData;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.net.Uri;
import android.os.Process;
import android.util.Log;
+import junit.framework.Assert;
+
+import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -40,15 +48,29 @@
/** Wait this long before timing out the test. */
private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
+ private JobParameters mParams;
+
+ ArrayList<Intent> mReceivedWork = new ArrayList<Intent>();
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (TestEnvironment.getTestEnvironment().getExpectedWork() != null) {
+ TestEnvironment.getTestEnvironment().notifyExecution(mParams, 0, 0, mReceivedWork,
+ null);
+ }
+ }
+
@Override
public void onCreate() {
super.onCreate();
- Log.e(TAG, "Created test service.");
+ Log.i(TAG, "Created test service.");
}
@Override
public boolean onStartJob(JobParameters params) {
Log.i(TAG, "Test job executing: " + params.getJobId());
+ mParams = params;
int permCheckRead = PackageManager.PERMISSION_DENIED;
int permCheckWrite = PackageManager.PERMISSION_DENIED;
@@ -60,8 +82,118 @@
Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
- TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, permCheckWrite);
- return false; // No work to do.
+ TestWorkItem[] expectedWork = TestEnvironment.getTestEnvironment().getExpectedWork();
+ if (expectedWork != null) {
+ try {
+ if (TestEnvironment.getTestEnvironment().awaitDoWork()) {
+ TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead,
+ permCheckWrite, null, "Spent too long waiting to start executing work");
+ return false;
+ }
+ } catch (InterruptedException e) {
+ TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead,
+ permCheckWrite, null, "Failed waiting for work: " + e);
+ return false;
+ }
+ JobWorkItem work;
+ int index = 0;
+ while ((work = params.dequeueWork()) != null) {
+ Log.i(TAG, "Received work #" + index + ": " + work.getIntent());
+ mReceivedWork.add(work.getIntent());
+
+ if (index < expectedWork.length) {
+ TestWorkItem expected = expectedWork[index];
+ int grantFlags = work.getIntent().getFlags();
+ if (expected.requireUrisGranted != null) {
+ for (int ui = 0; ui < expected.requireUrisGranted.length; ui++) {
+ if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (checkUriPermission(expected.requireUrisGranted[ui],
+ Process.myPid(), Process.myUid(),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ != PackageManager.PERMISSION_GRANTED) {
+ TestEnvironment.getTestEnvironment().notifyExecution(params,
+ permCheckRead, permCheckWrite, null,
+ "Expected read permission but not granted: "
+ + expected.requireUrisGranted[ui]
+ + " @ #" + index);
+ return false;
+ }
+ }
+ if ((grantFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (checkUriPermission(expected.requireUrisGranted[ui],
+ Process.myPid(), Process.myUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+ != PackageManager.PERMISSION_GRANTED) {
+ TestEnvironment.getTestEnvironment().notifyExecution(params,
+ permCheckRead, permCheckWrite, null,
+ "Expected write permission but not granted: "
+ + expected.requireUrisGranted[ui]
+ + " @ #" + index);
+ return false;
+ }
+ }
+ }
+ }
+ if (expected.requireUrisNotGranted != null) {
+ // XXX note no delay here, current impl will have fully revoked the
+ // permission by the time we return from completing the last work.
+ for (int ui = 0; ui < expected.requireUrisNotGranted.length; ui++) {
+ if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (checkUriPermission(expected.requireUrisNotGranted[ui],
+ Process.myPid(), Process.myUid(),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ != PackageManager.PERMISSION_DENIED) {
+ TestEnvironment.getTestEnvironment().notifyExecution(params,
+ permCheckRead, permCheckWrite, null,
+ "Not expected read permission but granted: "
+ + expected.requireUrisNotGranted[ui]
+ + " @ #" + index);
+ return false;
+ }
+ }
+ if ((grantFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (checkUriPermission(expected.requireUrisNotGranted[ui],
+ Process.myPid(), Process.myUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+ != PackageManager.PERMISSION_DENIED) {
+ TestEnvironment.getTestEnvironment().notifyExecution(params,
+ permCheckRead, permCheckWrite, null,
+ "Not expected write permission but granted: "
+ + expected.requireUrisNotGranted[ui]
+ + " @ #" + index);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ params.completeWork(work);
+
+ if (index < expectedWork.length) {
+ TestWorkItem expected = expectedWork[index];
+ if (expected.subitems != null) {
+ final TestWorkItem[] sub = expected.subitems;
+ final JobInfo ji = expected.jobInfo;
+ final JobScheduler js = (JobScheduler) getSystemService(
+ Context.JOB_SCHEDULER_SERVICE);
+ for (int subi = 0; subi < sub.length; subi++) {
+ js.enqueue(ji, new JobWorkItem(sub[subi].intent));
+ }
+ }
+ }
+
+ index++;
+ }
+ Log.i(TAG, "Done with all work at #" + index);
+ // We don't notifyExecution here because we want to make sure the job properly
+ // stops itself.
+ return true;
+ } else {
+ TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead,
+ permCheckWrite, null, null);
+ return false; // No work to do.
+ }
}
@Override
@@ -69,6 +201,39 @@
return false;
}
+ public static final class TestWorkItem {
+ public final Intent intent;
+ public final JobInfo jobInfo;
+ public final TestWorkItem[] subitems;
+ public final Uri[] requireUrisGranted;
+ public final Uri[] requireUrisNotGranted;
+
+ public TestWorkItem(Intent _intent) {
+ intent = _intent;
+ jobInfo = null;
+ subitems = null;
+ requireUrisGranted = null;
+ requireUrisNotGranted = null;
+ }
+
+ public TestWorkItem(Intent _intent, JobInfo _jobInfo, TestWorkItem[] _subitems) {
+ intent = _intent;
+ jobInfo = _jobInfo;
+ subitems = _subitems;
+ requireUrisGranted = null;
+ requireUrisNotGranted = null;
+ }
+
+ public TestWorkItem(Intent _intent, Uri[] _requireUrisGranted,
+ Uri[] _requireUrisNotGranted) {
+ intent = _intent;
+ jobInfo = null;
+ subitems = null;
+ requireUrisGranted = _requireUrisGranted;
+ requireUrisNotGranted = _requireUrisNotGranted;
+ }
+ }
+
/**
* Configures the expected behaviour for each test. This object is shared across consecutive
* tests, so to clear state each test is responsible for calling
@@ -80,9 +245,13 @@
//public static final int INVALID_JOB_ID = -1;
private CountDownLatch mLatch;
+ private CountDownLatch mDoWorkLatch;
+ private TestWorkItem[] mExpectedWork;
private JobParameters mExecutedJobParameters;
private int mExecutedPermCheckRead;
private int mExecutedPermCheckWrite;
+ private ArrayList<Intent> mExecutedReceivedWork;
+ private String mExecutedErrorMessage;
public static TestEnvironment getTestEnvironment() {
if (kTestEnvironment == null) {
@@ -91,6 +260,10 @@
return kTestEnvironment;
}
+ public TestWorkItem[] getExpectedWork() {
+ return mExpectedWork;
+ }
+
public JobParameters getLastJobParameters() {
return mExecutedJobParameters;
}
@@ -103,12 +276,23 @@
return mExecutedPermCheckWrite;
}
+ public ArrayList<Intent> getLastReceivedWork() {
+ return mExecutedReceivedWork;
+ }
+
+ public String getLastErrorMessage() {
+ return mExecutedErrorMessage;
+ }
+
/**
* Block the test thread, waiting on the JobScheduler to execute some previously scheduled
* job on this service.
*/
public boolean awaitExecution() throws InterruptedException {
final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ if (getLastErrorMessage() != null) {
+ Assert.fail(getLastErrorMessage());
+ }
return executed;
}
@@ -121,11 +305,18 @@
return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
}
- private void notifyExecution(JobParameters params, int permCheckRead, int permCheckWrite) {
+ public boolean awaitDoWork() throws InterruptedException {
+ return !mDoWorkLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ private void notifyExecution(JobParameters params, int permCheckRead, int permCheckWrite,
+ ArrayList<Intent> receivedWork, String errorMsg) {
//Log.d(TAG, "Job executed:" + params.getJobId());
mExecutedJobParameters = params;
mExecutedPermCheckRead = permCheckRead;
mExecutedPermCheckWrite = permCheckWrite;
+ mExecutedReceivedWork = receivedWork;
+ mExecutedErrorMessage = errorMsg;
mLatch.countDown();
}
@@ -138,6 +329,15 @@
}
}
+ public void setExpectedWork(TestWorkItem[] work) {
+ mExpectedWork = work;
+ mDoWorkLatch = new CountDownLatch(1);
+ }
+
+ public void readyToWork() {
+ mDoWorkLatch.countDown();
+ }
+
/** Called in each testCase#setup */
public void setUp() {
mLatch = null;
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
index be3f9c9..5ffa347 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
@@ -54,8 +54,6 @@
mBuilder = new JobInfo.Builder(BATTERY_JOB_ID, kJobServiceComponent);
SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler monitor-battery on");
- String res = SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
- + mContext.getPackageName() + " false");
}
@Override
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java
index 9a8b642..03d941e 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java
@@ -19,16 +19,10 @@
import android.annotation.TargetApi;
import android.app.job.JobInfo;
-import android.content.ClipData;
import android.content.ContentProviderClient;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.Bundle;
import android.os.Process;
-import android.os.SystemClock;
-
-import com.android.compatibility.common.util.SystemUtil;
/**
* Schedules jobs with the {@link android.app.job.JobScheduler} that grant permissions through
@@ -41,16 +35,7 @@
/** Unique identifier for the job scheduled by this suite of tests. */
public static final int CLIP_DATA_JOB_ID = ClipDataJobTest.class.hashCode();
- static final String MY_PACKAGE = "android.jobscheduler.cts";
-
- static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm";
- static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider";
- static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm";
-
- private JobInfo.Builder mBuilder;
- private Uri mFirstUri;
- private Bundle mFirstUriBundle;
- private ClipData mClipData;
+ JobInfo.Builder mBuilder;
private ContentProviderClient mProvider;
@Override
@@ -58,62 +43,15 @@
super.setUp();
mBuilder = new JobInfo.Builder(CLIP_DATA_JOB_ID, kJobServiceComponent);
- mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo");
- mFirstUriBundle = new Bundle();
- mFirstUriBundle.putParcelable("uri", mFirstUri);
- mClipData = new ClipData("JobPerm", new String[] { "application/*" },
- new ClipData.Item(mFirstUri));
mProvider = getContext().getContentResolver().acquireContentProviderClient(mFirstUri);
- String res = SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
- + mContext.getPackageName() + " false");
+ assertNotNull(mProvider);
}
@Override
public void tearDown() throws Exception {
+ super.tearDown();
mProvider.close();
mJobScheduler.cancel(CLIP_DATA_JOB_ID);
- // Put storage service back in to normal operation.
- SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
- }
-
- // Note we are just using storage state as a way to control when the job gets executed.
- void setStorageState(boolean low) throws Exception {
- String res;
- if (low) {
- res = SystemUtil.runShellCommand(getInstrumentation(),
- "cmd devicestoragemonitor force-low -f");
- } else {
- res = SystemUtil.runShellCommand(getInstrumentation(),
- "cmd devicestoragemonitor force-not-low -f");
- }
- int seq = Integer.parseInt(res.trim());
- long startTime = SystemClock.elapsedRealtime();
-
- // Wait for the storage update to be processed by job scheduler before proceeding.
- int curSeq;
- do {
- curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
- "cmd jobscheduler get-storage-seq").trim());
- if (curSeq == seq) {
- return;
- }
- } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
-
- fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
- }
-
- void waitPermissionRevoke(Uri uri, int access, long timeout) {
- long startTime = SystemClock.elapsedRealtime();
- while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access)
- != PackageManager.PERMISSION_GRANTED) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- }
- if ((SystemClock.elapsedRealtime()-startTime) >= timeout) {
- fail("Timed out waiting for permission revoke");
- }
- }
}
/**
@@ -135,7 +73,7 @@
// Schedule the job, the system should now also be holding a URI grant for us.
kTestEnvironment.setExpectedExecutions(1);
mJobScheduler.schedule(mBuilder.setRequiresStorageNotLow(true)
- .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
// Remove the explicit grant, we should still have a grant due to the job.
@@ -167,7 +105,7 @@
public void testClipDataGrant_Failed() throws Exception {
try {
mJobScheduler.schedule(mBuilder.setRequiresStorageNotLow(true)
- .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
} catch (SecurityException e) {
return;
@@ -193,7 +131,7 @@
// Schedule the job, the system should now also be holding a URI grant for us.
kTestEnvironment.setExpectedExecutions(1);
mJobScheduler.schedule(mBuilder.setMinimumLatency(60*60*1000)
- .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
// Remove the explicit grant, we should still have a grant due to the job.
@@ -207,7 +145,7 @@
// Now reschedule the job to have it happen right now.
mJobScheduler.schedule(mBuilder.setMinimumLatency(0)
- .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
assertTrue("Job with storage not low constraint did not fire when storage not low.",
kTestEnvironment.awaitExecution());
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index a7c7003..0a3ff9c 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -163,6 +163,27 @@
kTestEnvironment.awaitExecution());
}
+ /**
+ * Schedule a job with a metered connectivity constraint, and ensure that it executes
+ * on on a mobile data connection.
+ */
+ public void testConnectivityConstraintExecutes_metered() throws Exception {
+ if (!checkDeviceSupportsMobileData()) {
+ return;
+ }
+ disconnectWifiToConnectToMobile();
+
+ kTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(
+ mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED)
+ .build());
+
+ sendExpediteStableChargingBroadcast();
+
+ assertTrue("Job with metered connectivity constraint did not fire on mobile.",
+ kTestEnvironment.awaitExecution());
+ }
+
// --------------------------------------------------------------------------------------------
// Negatives - schedule jobs under conditions that require that they fail.
// --------------------------------------------------------------------------------------------
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
index b2cf29c..bcc1e08 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
@@ -18,13 +18,23 @@
import android.annotation.TargetApi;
import android.app.Instrumentation;
import android.app.job.JobScheduler;
+import android.content.ClipData;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.jobscheduler.MockJobService;
import android.jobscheduler.TriggerContentJobService;
-import android.test.AndroidTestCase;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.SystemClock;
import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import java.io.IOException;
/**
* Common functionality from which the other test case classes derive.
@@ -47,10 +57,45 @@
Context mContext;
+ static final String MY_PACKAGE = "android.jobscheduler.cts";
+
+ static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm";
+ static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider";
+ static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm";
+
+ Uri mFirstUri;
+ Bundle mFirstUriBundle;
+ Uri mSecondUri;
+ Bundle mSecondUriBundle;
+ ClipData mFirstClipData;
+ ClipData mSecondClipData;
+
+ boolean mStorageStateChanged;
+
@Override
public void injectInstrumentation(Instrumentation instrumentation) {
super.injectInstrumentation(instrumentation);
mContext = instrumentation.getContext();
+ kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
+ kTriggerContentServiceComponent = new ComponentName(getContext(),
+ TriggerContentJobService.class);
+ mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo");
+ mFirstUriBundle = new Bundle();
+ mFirstUriBundle.putParcelable("uri", mFirstUri);
+ mSecondUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/bar");
+ mSecondUriBundle = new Bundle();
+ mSecondUriBundle.putParcelable("uri", mSecondUri);
+ mFirstClipData = new ClipData("JobPerm1", new String[] { "application/*" },
+ new ClipData.Item(mFirstUri));
+ mSecondClipData = new ClipData("JobPerm2", new String[] { "application/*" },
+ new ClipData.Item(mSecondUri));
+ try {
+ SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
+ + mContext.getPackageName() + " false");
+ } catch (IOException e) {
+ Log.w("ConstraintTest", "Failed setting inactive false", e);
+ }
}
public Context getContext() {
@@ -62,13 +107,18 @@
super.setUp();
kTestEnvironment.setUp();
kTriggerTestEnvironment.setUp();
- kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
- kTriggerContentServiceComponent = new ComponentName(getContext(),
- TriggerContentJobService.class);
- mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
mJobScheduler.cancelAll();
}
+ @Override
+ public void tearDown() throws Exception {
+ if (mStorageStateChanged) {
+ // Put storage service back in to normal operation.
+ SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
+ mStorageStateChanged = false;
+ }
+ }
+
/**
* The scheduler will usually only flush its queue of unexpired jobs when the device is
* considered to be on stable power - that is, plugged in for a period of 2 minutes.
@@ -77,4 +127,58 @@
protected void sendExpediteStableChargingBroadcast() {
getContext().sendBroadcast(EXPEDITE_STABLE_CHARGING);
}
+
+ public void assertHasUriPermission(Uri uri, int grantFlags) {
+ if ((grantFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ getContext().checkUriPermission(uri, Process.myPid(),
+ Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION));
+ }
+ if ((grantFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ getContext().checkUriPermission(uri, Process.myPid(),
+ Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
+ }
+ }
+
+ void waitPermissionRevoke(Uri uri, int access, long timeout) {
+ long startTime = SystemClock.elapsedRealtime();
+ while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access)
+ != PackageManager.PERMISSION_DENIED) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ }
+ if ((SystemClock.elapsedRealtime()-startTime) >= timeout) {
+ fail("Timed out waiting for permission revoke");
+ }
+ }
+ }
+
+ // Note we are just using storage state as a way to control when the job gets executed.
+ void setStorageState(boolean low) throws Exception {
+ mStorageStateChanged = true;
+ String res;
+ if (low) {
+ res = SystemUtil.runShellCommand(getInstrumentation(),
+ "cmd devicestoragemonitor force-low -f");
+ } else {
+ res = SystemUtil.runShellCommand(getInstrumentation(),
+ "cmd devicestoragemonitor force-not-low -f");
+ }
+ int seq = Integer.parseInt(res.trim());
+ long startTime = SystemClock.elapsedRealtime();
+
+ // Wait for the storage update to be processed by job scheduler before proceeding.
+ int curSeq;
+ do {
+ curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
+ "cmd jobscheduler get-storage-seq").trim());
+ if (curSeq == seq) {
+ return;
+ }
+ } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
+
+ fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
+ }
}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/EnqueueJobWorkTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/EnqueueJobWorkTest.java
new file mode 100644
index 0000000..402233b
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/EnqueueJobWorkTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.jobscheduler.cts;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobWorkItem;
+import android.content.ContentProviderClient;
+import android.content.Intent;
+import android.jobscheduler.MockJobService.TestWorkItem;
+import android.net.Uri;
+
+import java.util.ArrayList;
+
+/**
+ * Schedules jobs with the {@link android.app.job.JobScheduler} by enqueue work in to
+ * them and processing it.
+ */
+@TargetApi(26)
+public class EnqueueJobWorkTest extends ConstraintTest {
+ private static final String TAG = "ClipDataJobTest";
+
+ /** Unique identifier for the job scheduled by this suite of tests. */
+ public static final int ENQUEUE_WORK_JOB_ID = EnqueueJobWorkTest.class.hashCode();
+
+ private JobInfo.Builder mBuilder;
+ private ContentProviderClient mProvider;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mBuilder = new JobInfo.Builder(ENQUEUE_WORK_JOB_ID, kJobServiceComponent);
+ mProvider = getContext().getContentResolver().acquireContentProviderClient(mFirstUri);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ mProvider.close();
+ mJobScheduler.cancel(ENQUEUE_WORK_JOB_ID);
+ }
+
+ private boolean intentEquals(Intent i1, Intent i2) {
+ if (i1 == i2) {
+ return true;
+ }
+ if (i1 == null || i2 == null) {
+ return false;
+ }
+ return i1.filterEquals(i2);
+ }
+
+ private void compareWork(TestWorkItem[] expected, ArrayList<Intent> received) {
+ if (received == null) {
+ fail("Didn't receive any expected work.");
+ }
+ ArrayList<TestWorkItem> expectedArray = new ArrayList<>();
+ for (int i = 0; i < expected.length; i++) {
+ expectedArray.add(expected[i]);
+ }
+ for (int i = 0; i < received.size(); i++) {
+ Intent work = received.get(i);
+ if (i < expected.length && expected[i].subitems != null) {
+ TestWorkItem[] sub = expected[i].subitems;
+ for (int j = 0; j < sub.length; j++) {
+ expectedArray.add(sub[j]);
+ }
+ }
+ if (i >= expectedArray.size()) {
+ fail("Received more than " + expected.length + " work items, first extra is "
+ + work);
+ }
+ if (!intentEquals(work, expectedArray.get(i).intent)) {
+ fail("Received work #" + i + " " + work + " but expected " + expected[i]);
+ }
+ }
+ if (received.size() < expected.length) {
+ fail("Received only " + received.size() + " work items, but expected "
+ + expected.length);
+ }
+ }
+
+ /**
+ * Test basic enqueueing of work.
+ */
+ public void testEnqueueOneWork() throws Exception {
+ Intent work1 = new Intent("work1");
+ TestWorkItem[] work = new TestWorkItem[] { new TestWorkItem(work1) };
+ kTestEnvironment.setExpectedExecutions(1);
+ kTestEnvironment.setExpectedWork(work);
+ mJobScheduler.enqueue(mBuilder.setOverrideDeadline(0).build(), new JobWorkItem(work1));
+ kTestEnvironment.readyToWork();
+ assertTrue("Job with work enqueued did not fire.",
+ kTestEnvironment.awaitExecution());
+ compareWork(work, kTestEnvironment.getLastReceivedWork());
+ if (kTestEnvironment.getLastErrorMessage() != null) {
+ fail(kTestEnvironment.getLastErrorMessage());
+ }
+ }
+
+ /**
+ * Test basic enqueueing batches of work.
+ */
+ public void testEnqueueMultipleWork() throws Exception {
+ Intent work1 = new Intent("work1");
+ Intent work2 = new Intent("work2");
+ Intent work3 = new Intent("work3");
+ Intent work4 = new Intent("work4");
+ Intent work5 = new Intent("work5");
+ Intent work6 = new Intent("work6");
+ Intent work7 = new Intent("work7");
+ Intent work8 = new Intent("work8");
+ TestWorkItem[] work = new TestWorkItem[] {
+ new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
+ new TestWorkItem(work4), new TestWorkItem(work5), new TestWorkItem(work6),
+ new TestWorkItem(work7), new TestWorkItem(work8) };
+ kTestEnvironment.setExpectedExecutions(1);
+ kTestEnvironment.setExpectedWork(work);
+ JobInfo ji = mBuilder.setOverrideDeadline(0).build();
+ mJobScheduler.enqueue(ji, new JobWorkItem(work1));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work2));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work3));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work4));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work5));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work6));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work7));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work8));
+ kTestEnvironment.readyToWork();
+ assertTrue("Job with work enqueued did not fire.",
+ kTestEnvironment.awaitExecution());
+ compareWork(work, kTestEnvironment.getLastReceivedWork());
+ }
+
+ /**
+ * Test basic enqueueing batches of work, with new work coming in while processing existing
+ * work.
+ */
+ public void testEnqueueMultipleSubWork() throws Exception {
+ Intent work1 = new Intent("work1");
+ Intent work2 = new Intent("work2");
+ Intent work3 = new Intent("work3");
+ Intent work4 = new Intent("work4");
+ Intent work5 = new Intent("work5");
+ Intent work6 = new Intent("work6");
+ Intent work7 = new Intent("work7");
+ Intent work8 = new Intent("work8");
+ JobInfo ji = mBuilder.setOverrideDeadline(0).build();
+ TestWorkItem[] work = new TestWorkItem[]{
+ new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
+ new TestWorkItem(work4, ji, new TestWorkItem[] {
+ new TestWorkItem(work5), new TestWorkItem(work6),
+ new TestWorkItem(work7), new TestWorkItem(work8)})
+ };
+ kTestEnvironment.setExpectedExecutions(1);
+ kTestEnvironment.setExpectedWork(work);
+ mJobScheduler.enqueue(ji, new JobWorkItem(work1));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work2));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work3));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work4));
+ kTestEnvironment.readyToWork();
+ assertTrue("Job with work enqueued did not fire.",
+ kTestEnvironment.awaitExecution());
+ compareWork(work, kTestEnvironment.getLastReceivedWork());
+ }
+
+ /**
+ * Test basic enqueueing batches of work.
+ */
+ public void testEnqueueMultipleUriGrantWork() throws Exception {
+ // Start out with storage low, so job is enqueued but not executed yet.
+ setStorageState(true);
+
+ // We need to get a permission grant so that we can grant it to ourself.
+ mProvider.call("grant", MY_PACKAGE, mFirstUriBundle);
+ mProvider.call("grant", MY_PACKAGE, mSecondUriBundle);
+ assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ Intent work1 = new Intent("work1");
+ work1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ work1.setData(mFirstUri);
+ work1.setClipData(mSecondClipData);
+
+ Intent work2 = new Intent("work2");
+ work2.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ work2.setData(mFirstUri);
+
+ TestWorkItem[] work = new TestWorkItem[] {
+ new TestWorkItem(work1, new Uri[] { mFirstUri, mSecondUri}, new Uri[0]),
+ new TestWorkItem(work2, new Uri[] { mFirstUri }, new Uri[] { mSecondUri}) };
+ kTestEnvironment.setExpectedExecutions(1);
+ kTestEnvironment.setExpectedWork(work);
+ JobInfo ji = mBuilder.setOverrideDeadline(0).setRequiresStorageNotLow(true).build();
+ mJobScheduler.enqueue(ji, new JobWorkItem(work1));
+ mJobScheduler.enqueue(ji, new JobWorkItem(work2));
+
+ // Remove the explicit grant, we should still have a grant due to the job.
+ mProvider.call("revoke", MY_PACKAGE, mFirstUriBundle);
+ mProvider.call("revoke", MY_PACKAGE, mSecondUriBundle);
+ assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ kTestEnvironment.readyToWork();
+
+ // Now allow the job to run.
+ setStorageState(false);
+
+ assertTrue("Job with work enqueued did not fire.",
+ kTestEnvironment.awaitExecution());
+ compareWork(work, kTestEnvironment.getLastReceivedWork());
+
+ // And wait for everything to be cleaned up.
+ waitPermissionRevoke(mFirstUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
+ waitPermissionRevoke(mSecondUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
+ }
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java
index f40dd66..aea4d84 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java
@@ -40,40 +40,12 @@
super.setUp();
mBuilder = new JobInfo.Builder(STORAGE_JOB_ID, kJobServiceComponent);
- String res = SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
- + mContext.getPackageName() + " false");
}
@Override
public void tearDown() throws Exception {
+ super.tearDown();
mJobScheduler.cancel(STORAGE_JOB_ID);
- // Put storage service back in to normal operation.
- SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
- }
-
- void setStorageState(boolean low) throws Exception {
- String res;
- if (low) {
- res = SystemUtil.runShellCommand(getInstrumentation(),
- "cmd devicestoragemonitor force-low -f");
- } else {
- res = SystemUtil.runShellCommand(getInstrumentation(),
- "cmd devicestoragemonitor force-not-low -f");
- }
- int seq = Integer.parseInt(res.trim());
- long startTime = SystemClock.elapsedRealtime();
-
- // Wait for the storage update to be processed by job scheduler before proceeding.
- int curSeq;
- do {
- curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
- "cmd jobscheduler get-storage-seq").trim());
- if (curSeq == seq) {
- return;
- }
- } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
-
- fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
}
// --------------------------------------------------------------------------------------------
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
index 8b71171..fe48950 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
@@ -42,7 +42,7 @@
*/
@TargetApi(23)
public class TriggerContentTest extends ConstraintTest {
- public static final int TRIGGER_CONTENT_JOB_ID = ConnectivityConstraintTest.class.hashCode();
+ public static final int TRIGGER_CONTENT_JOB_ID = TriggerContentTest.class.hashCode();
// The root URI of the media provider, to monitor for generic changes to its content.
static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/");
@@ -120,7 +120,7 @@
}
@Override
- protected void tearDown() throws Exception {
+ public void tearDown() throws Exception {
super.tearDown();
for (int i=0; i<mActiveFiles.length; i++) {
cleanupActive(i);
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1185813..1979e97 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -23,7 +23,6 @@
import android.test.InstrumentationTestCase;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
@@ -83,15 +82,6 @@
assertFalse(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
}
- public void testAddAndRemoveServiceStateChangeListener() throws Exception {
- AccessibilityServicesStateChangeListener listener = () -> {
- // Do Nothing
- };
- assertTrue(mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener));
- assertTrue(mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener));
- assertFalse(mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener));
- }
-
public void testIsTouchExplorationEnabled() throws Exception {
new PollingCheck() {
@Override
@@ -240,44 +230,6 @@
waitForTouchExplorationEnabled();
}
- public void testServiceStateChanges_stateChangeListenersCalled() throws Exception {
- final Object waitObject = new Object();
- final AtomicBoolean listenerCalled = new AtomicBoolean(false);
- final SpeakingAccessibilityService service =
- SpeakingAccessibilityService.sConnectedInstance;
- final AccessibilityServicesStateChangeListener listener = () -> {
- synchronized (waitObject) {
- listenerCalled.set(true);
- waitObject.notifyAll();
- }
- };
-
- mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener);
- // Verify called on info change
- final AccessibilityServiceInfo initialInfo = service.getServiceInfo();
- AccessibilityServiceInfo tempInfo = service.getServiceInfo();
- tempInfo.flags ^= AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
- try {
- service.setServiceInfo(tempInfo);
- assertListenerCalled(listenerCalled, waitObject);
- } finally {
- service.setServiceInfo(initialInfo);
- }
-
- // Verify called on service disabled
- listenerCalled.set(false);
- ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
- assertListenerCalled(listenerCalled, waitObject);
-
- // Verify called on service enabled
- listenerCalled.set(false);
- ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
- assertListenerCalled(listenerCalled, waitObject);
-
- mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener);
-
- }
-
private void assertListenerCalled(AtomicBoolean listenerCalled, Object waitObject)
throws Exception {
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
diff --git a/tests/app/src/android/app/cts/ActionBarTest.java b/tests/app/src/android/app/cts/ActionBarTest.java
index e6da6cb..351339b 100644
--- a/tests/app/src/android/app/cts/ActionBarTest.java
+++ b/tests/app/src/android/app/cts/ActionBarTest.java
@@ -24,6 +24,7 @@
import android.test.UiThreadTest;
import android.view.KeyEvent;
import android.view.Window;
+import org.junit.Assume;
public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
@@ -84,6 +85,7 @@
}
public void testOptionsMenuKey() {
+ Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
final boolean menuIsVisible[] = {false};
mActivity.getActionBar().addOnMenuVisibilityListener(
isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index e3e7c53..f29ae1e 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ConfigurationInfo;
+import android.content.res.Resources;
import android.platform.test.annotations.RestrictedBuildTest;
import android.test.InstrumentationTestCase;
@@ -398,6 +399,20 @@
Thread.sleep(WAIT_TIME);
}
+ /**
+ * Gets the value of com.android.internal.R.bool.config_noHomeScreen.
+ * @return true if no home screen is supported, false otherwise.
+ */
+ private boolean noHomeScreen() {
+ try {
+ return getInstrumentation().getContext().getResources().getBoolean(
+ Resources.getSystem().getIdentifier("config_noHomeScreen", "bool", "android"));
+ } catch (Resources.NotFoundException e) {
+ // Assume there's a home screen.
+ return false;
+ }
+ }
+
/**
* Verify that the TimeTrackingAPI works properly when starting and ending an activity.
*/
@@ -429,10 +444,20 @@
assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
appEndReceiver.close();
- // At this time the timerReceiver should not fire, even though the activity has shut down,
- // because we are back to the home screen.
- assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
- assertTrue(timeReceiver.mTimeUsed == 0);
+ if (!noHomeScreen()) {
+ // At this time the timerReceiver should not fire, even though the activity has shut
+ // down, because we are back to the home screen. Going to the home screen does not
+ // qualify as the user leaving the activity's flow. The time tracking is considered
+ // complete only when the user switches to another activity that is not part of the
+ // tracked flow.
+ assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+ assertTrue(timeReceiver.mTimeUsed == 0);
+ } else {
+ // With platforms that have no home screen, focus is returned to something else that is
+ // considered a completion of the tracked activity flow, and hence time tracking is
+ // triggered.
+ assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+ }
// Issuing now another activity will trigger the timing information release.
final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
@@ -525,9 +550,20 @@
assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
appEndReceiver.close();
- // At this time the timerReceiver should not fire, even though the activity has shut down.
- assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
- assertTrue(timeReceiver.mTimeUsed == 0);
+ if (!noHomeScreen()) {
+ // At this time the timerReceiver should not fire, even though the activity has shut
+ // down, because we are back to the home screen. Going to the home screen does not
+ // qualify as the user leaving the activity's flow. The time tracking is considered
+ // complete only when the user switches to another activity that is not part of the
+ // tracked flow.
+ assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+ assertTrue(timeReceiver.mTimeUsed == 0);
+ } else {
+ // With platforms that have no home screen, focus is returned to something else that is
+ // considered a completion of the tracked activity flow, and hence time tracking is
+ // triggered.
+ assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+ }
// Issue another activity so that the timing information gets released.
final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
diff --git a/tests/app/src/android/app/cts/AlertWindowsTests.java b/tests/app/src/android/app/cts/AlertWindowsTests.java
index 6d76d3b..f7c8ff8 100644
--- a/tests/app/src/android/app/cts/AlertWindowsTests.java
+++ b/tests/app/src/android/app/cts/AlertWindowsTests.java
@@ -17,41 +17,48 @@
package android.app.cts;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE_DEPRECATED;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
import static android.content.Context.BIND_ALLOW_OOM_MANAGEMENT;
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_NOT_FOREGROUND;
+
import static com.android.app2.AlertWindowService.MSG_ADD_ALERT_WINDOW;
import static com.android.app2.AlertWindowService.MSG_ON_ALERT_WINDOW_ADDED;
import static com.android.app2.AlertWindowService.MSG_ON_ALERT_WINDOW_REMOVED;
import static com.android.app2.AlertWindowService.MSG_REMOVE_ALERT_WINDOW;
import static com.android.app2.AlertWindowService.MSG_REMOVE_ALL_ALERT_WINDOWS;
import static com.android.app2.AlertWindowService.NOTIFICATION_MESSENGER_EXTRA;
+
import static org.junit.Assert.assertEquals;
-import android.platform.test.annotations.Presubmit;
-import com.android.app2.AlertWindowService;
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import com.android.app2.AlertWindowService;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Function;
+
/**
* Build: mmma -j32 cts/tests/app
* Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsAppTestCases android.app.cts.AlertWindowsTests
@@ -61,12 +68,20 @@
public class AlertWindowsTests {
private static final String TAG = "AlertWindowsTests";
+
private static final boolean DEBUG = false;
private static final long WAIT_TIME_MS = 2 * 1000;
+ private static final String SDK25_PACKAGE_NAME = "com.android.appSdk25";
+
private Messenger mService;
private String mServicePackageName;
+ private int mServiceUid;
+
+ private PackageManager mPm;
+
private ActivityManager mAm;
+ private ActivityManager mAm25; // ActivityManager created for an SDK 25 app context.
private final Messenger mMessenger = new Messenger(new IncomingHandler(Looper.getMainLooper()));
private final Object mAddedLock = new Object();
@@ -76,7 +91,12 @@
public void setUp() throws Exception {
if (DEBUG) Log.e(TAG, "setUp");
final Context context = InstrumentationRegistry.getTargetContext();
+
+ mPm = context.getPackageManager();
+
mAm = context.getSystemService(ActivityManager.class);
+ mAm25 = context.createPackageContext(SDK25_PACKAGE_NAME, 0)
+ .getSystemService(ActivityManager.class);
final Intent intent = new Intent();
intent.setClassName(AlertWindowService.class.getPackage().getName(),
@@ -107,27 +127,34 @@
public void testAlertWindowOomAdj() throws Exception {
setAlertWindowPermission(true /* allow */);
- assertImportance(IMPORTANCE_PERCEPTIBLE);
+ assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
+ assertUidImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
+
addAlertWindow();
// Process importance should be increased to visible when the service has an alert window.
- assertImportance(IMPORTANCE_VISIBLE);
+ assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
+
+ // TODO: Somehow getUidImportance still returns 230 (IMPORTANCE_PERCEPTIBLE) instead of
+ // IMPORTANCE_VISIBLE(200)
+ // assertUidImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
+
addAlertWindow();
- assertImportance(IMPORTANCE_VISIBLE);
+ assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
setAlertWindowPermission(false /* allow */);
// Process importance should no longer be visible since its alert windows are not allowed to
// be visible.
- assertImportance(IMPORTANCE_PERCEPTIBLE);
+ assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
setAlertWindowPermission(true /* allow */);
// They can show again so importance should be visible again.
- assertImportance(IMPORTANCE_VISIBLE);
+ assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
removeAlertWindow();
- assertImportance(IMPORTANCE_VISIBLE);
+ assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
removeAlertWindow();
// Process importance should no longer be visible when the service no longer as alert
// windows.
- assertImportance(IMPORTANCE_PERCEPTIBLE);
+ assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
}
private void addAlertWindow() throws Exception {
@@ -152,7 +179,8 @@
SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
}
- private void assertImportance(int expected) throws Exception {
+ private void assertImportance(Function<ActivityManager, Integer> apiCaller,
+ int expectedForO, int expectedForPreO) throws Exception {
int retry = 3;
int actual;
@@ -161,10 +189,29 @@
// for changes in the uid importance. However, the way it is currently structured
// doesn't really work for this use case right now...
Thread.sleep(500);
- actual = mAm.getPackageImportance(mServicePackageName);
- } while (actual != expected && --retry > 0);
+ actual = apiCaller.apply(mAm);
+ } while (actual != expectedForO && --retry > 0);
- assertEquals(expected, actual);
+ assertEquals(expectedForO, actual);
+
+ // Check the result for pre-O apps.
+ assertEquals(expectedForPreO, (int) apiCaller.apply(mAm25));
+ }
+
+ /**
+ * Make sure {@link ActivityManager#getPackageImportance} returns the expected value.
+ */
+ private void assertPackageImportance(int expectedForO, int expectedForPreO) throws Exception {
+ assertImportance(am -> am.getPackageImportance(mServicePackageName),
+ expectedForO, expectedForPreO);
+ }
+
+ /**
+ * Make sure {@link ActivityManager#getUidImportance(int)} returns the expected value.
+ */
+ private void assertUidImportance(int expectedForO, int expectedForPreO) throws Exception {
+ assertImportance(am -> am.getUidImportance(mServiceUid),
+ expectedForO, expectedForPreO);
}
private final ServiceConnection mConnection = new ServiceConnection() {
@@ -173,6 +220,11 @@
if (DEBUG) Log.e(TAG, "onServiceConnected");
mService = new Messenger(service);
mServicePackageName = name.getPackageName();
+ try {
+ mServiceUid = mPm.getPackageUid(mServicePackageName, 0);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException("getPackageUid() failed.", e);
+ }
synchronized (mConnection) {
notifyAll();
}
@@ -183,6 +235,7 @@
if (DEBUG) Log.e(TAG, "onServiceDisconnected");
mService = null;
mServicePackageName = null;
+ mServiceUid = 0;
}
};
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 74047be..70ec9cf 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -25,6 +25,7 @@
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Parcel;
+import android.provider.Settings;
import android.test.AndroidTestCase;
public class NotificationChannelTest extends AndroidTestCase {
@@ -52,7 +53,7 @@
assertEquals(false, channel.shouldVibrate());
assertEquals(null, channel.getVibrationPattern());
assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
- assertEquals(null, channel.getSound());
+ assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, channel.getSound());
assertTrue(channel.canShowBadge());
assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, channel.getAudioAttributes());
assertEquals(null, channel.getGroup());
diff --git a/tests/app/src/android/app/cts/ToolbarActionBarTest.java b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
index 53ee982..d625802 100644
--- a/tests/app/src/android/app/cts/ToolbarActionBarTest.java
+++ b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
@@ -21,6 +21,7 @@
import android.view.KeyEvent;
import android.view.Window;
+import org.junit.Assume;
public class ToolbarActionBarTest extends ActivityInstrumentationTestCase2<ToolbarActivity> {
@@ -39,6 +40,7 @@
}
public void testOptionsMenuKey() {
+ Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
final boolean menuIsVisible[] = {false};
mActivity.getActionBar().addOnMenuVisibilityListener(
isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index aca9453..32bf5a5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -31,6 +31,7 @@
<activity android:name=".WelcomeActivity"/>
<activity android:name=".ViewAttributesTestActivity" />
<activity android:name=".AuthenticationActivity" />
+ <activity android:name=".ManualAuthenticationActivity" />
<activity android:name=".CheckoutActivity"/>
<activity android:name=".InitializedCheckoutActivity" />
<activity android:name=".DatePickerCalendarActivity" />
@@ -49,6 +50,11 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:name=".EmptyActivity"/>
+ <activity android:name=".DummyActivity"/>
+ <activity android:name=".OutOfProcessLoginActivity"
+ android:process="android.autofillservice.cts.outside"/>
+ <activity android:name=".FragmentContainerActivity" />
<service
android:name=".InstrumentedAutoFillService"
diff --git a/tests/autofillservice/res/layout/empty.xml b/tests/autofillservice/res/layout/empty.xml
new file mode 100644
index 0000000..7687408
--- /dev/null
+++ b/tests/autofillservice/res/layout/empty.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/tests/autofillservice/res/layout/fragment_container.xml b/tests/autofillservice/res/layout/fragment_container.xml
new file mode 100644
index 0000000..156efad
--- /dev/null
+++ b/tests/autofillservice/res/layout/fragment_container.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/rootContainer" />
diff --git a/tests/autofillservice/res/layout/fragment_with_edittext.xml b/tests/autofillservice/res/layout/fragment_with_edittext.xml
new file mode 100644
index 0000000..e0d4584
--- /dev/null
+++ b/tests/autofillservice/res/layout/fragment_with_edittext.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <EditText android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/editText1" />
+
+ <EditText android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/editText2" />
+</LinearLayout>
diff --git a/tests/autofillservice/res/layout/single_button_activity.xml b/tests/autofillservice/res/layout/single_button_activity.xml
new file mode 100644
index 0000000..9c68b98
--- /dev/null
+++ b/tests/autofillservice/res/layout/single_button_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="press me"
+ android:id="@+id/button" />
+</LinearLayout>
diff --git a/tests/autofillservice/res/layout/view_attribute_test_activity.xml b/tests/autofillservice/res/layout/view_attribute_test_activity.xml
index e383d6c..96c0186 100644
--- a/tests/autofillservice/res/layout/view_attribute_test_activity.xml
+++ b/tests/autofillservice/res/layout/view_attribute_test_activity.xml
@@ -19,34 +19,6 @@
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:id="@+id/rootContainer">
- <EditText android:id="@+id/firstLevelDefault" android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <EditText android:id="@+id/firstLevelInherit" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="inherit" />
-
- <EditText android:id="@+id/firstLevelAuto" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="auto" />
-
- <EditText android:id="@+id/firstLevelManual" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="manual" />
-
- <LinearLayout android:id="@+id/manualContainer" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="manual"
- android:orientation="vertical">
- <EditText android:id="@+id/manualContainerDefault" android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <EditText android:id="@+id/manualContainerInherit" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="inherit" />
-
- <EditText android:id="@+id/manualContainerAuto" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="auto" />
-
- <EditText android:id="@+id/manualContainerManual" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:autofillMode="manual" />
- </LinearLayout>
-
<TextView android:id="@+id/textViewNoHint" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:id="@+id/textViewHintCustom" android:layout_width="wrap_content"
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
index f0b56d4..efc0b2c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
@@ -50,8 +50,8 @@
});
try {
if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
- throw new AssertionError(
- "action on UI thread timed out after " + timeoutMs + " ms");
+ throw new RetryableException("action on UI thread timed out after %d ms",
+ timeoutMs);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index df61e37..d18e621 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -32,6 +32,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.runner.RunWith;
/**
@@ -48,6 +49,9 @@
protected static final Replier sReplier = InstrumentedAutoFillService.getReplier();
+ @Rule
+ public final RetryRule mRetryRule = new RetryRule(2);
+
@BeforeClass
public static void removeLockScreen() {
runShellCommand("input keyevent KEYCODE_WAKEUP");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
new file mode 100644
index 0000000..4a0e992
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import static android.autofillservice.cts.FragmentContainerActivity.FRAGMENT_TAG;
+import static android.autofillservice.cts.Helper.FILL_TIMEOUT_MS;
+import static android.autofillservice.cts.Helper.eventually;
+import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Fragment;
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.content.Intent;
+import android.service.autofill.SaveInfo;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.rule.ActivityTestRule;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Tests that the session finishes when the views and fragments go away
+ */
+public class AutoFinishSessionTest extends AutoFillServiceTestCase {
+ @Rule
+ public final ActivityTestRule<FragmentContainerActivity> mActivityRule =
+ new ActivityTestRule<>(FragmentContainerActivity.class);
+ private FragmentContainerActivity mActivity;
+ private EditText mEditText1;
+ private EditText mEditText2;
+ private Fragment mFragment;
+ private ViewGroup mParent;
+
+ @Before
+ public void initViews() {
+ mActivity = mActivityRule.getActivity();
+ mEditText1 = mActivity.findViewById(R.id.editText1);
+ mEditText2 = mActivity.findViewById(R.id.editText2);
+ mFragment = mActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
+ mParent = ((ViewGroup) mEditText1.getParent());
+
+ assertThat(mFragment).isNotNull();
+ }
+
+ private void removeViewsBaseTest(@NonNull Runnable firstRemove, @Nullable Runnable firstCheck,
+ @Nullable Runnable secondRemove, String... viewsToSave)
+ throws Exception {
+ enableService();
+ try {
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE)
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, viewsToSave).build());
+
+ // Trigger autofill
+ eventually(() -> {
+ mActivity.syncRunOnUiThread(() -> mEditText2.requestFocus());
+ mActivity.syncRunOnUiThread(() -> mEditText1.requestFocus());
+
+ try {
+ sReplier.getNextFillRequest();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }, (int) (FILL_TIMEOUT_MS * 2));
+
+ sUiBot.assertNoDatasets();
+
+ // remove first set of views
+ mActivity.syncRunOnUiThread(() -> {
+ mEditText1.setText("editText1-filled");
+ mEditText2.setText("editText2-filled");
+ });
+ firstRemove.run();
+
+ // Check state between remove operations
+ if (firstCheck != null) {
+ firstCheck.run();
+ }
+
+ // remove second set of views
+ if (secondRemove != null) {
+ secondRemove.run();
+ }
+
+ // Save should be shows after all remove operations were executed
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+
+ SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ for (String view : viewsToSave) {
+ assertThat(findNodeByResourceId(saveRequest.structure, view)
+ .getAutofillValue().getTextValue().toString()).isEqualTo(view + "-filled");
+ }
+ } finally {
+ disableService();
+ }
+ }
+
+ @Test
+ public void removeBothViewsToFinishSession() throws Exception {
+ removeViewsBaseTest(
+ () -> mActivity.syncRunOnUiThread(
+ () -> ((ViewGroup) mEditText1.getParent()).removeView(mEditText1)),
+ () -> sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC),
+ () -> mActivity.syncRunOnUiThread(
+ () -> ((ViewGroup) mEditText2.getParent()).removeView(mEditText2)),
+ "editText1", "editText2");
+ }
+
+ @Test
+ public void removeOneViewToFinishSession() throws Exception {
+ removeViewsBaseTest(
+ () -> mActivity.syncRunOnUiThread(() -> {
+ // Do not trigger new partition when switching to editText2
+ mEditText2.setFocusable(false);
+
+ mParent.removeView(mEditText1);
+ }),
+ null,
+ null,
+ "editText1");
+ }
+
+ @Test
+ public void hideOneViewToFinishSession() throws Exception {
+ removeViewsBaseTest(
+ () -> mActivity.syncRunOnUiThread(
+ () -> mEditText1.setVisibility(ViewGroup.INVISIBLE)),
+ null,
+ null,
+ "editText1");
+ }
+
+ @Test
+ public void removeFragmentToFinishSession() throws Exception {
+ removeViewsBaseTest(
+ () -> mActivity.syncRunOnUiThread(
+ () -> mActivity.getFragmentManager().beginTransaction().remove(
+ mFragment).commitNow()),
+ null,
+ null,
+ "editText1", "editText2");
+ }
+
+ @Test
+ public void removeParentToFinishSession() throws Exception {
+ removeViewsBaseTest(
+ () -> mActivity.syncRunOnUiThread(
+ () -> ((ViewGroup) mParent.getParent()).removeView(mParent)),
+ null,
+ null,
+ "editText1", "editText2");
+ }
+
+ @Test
+ public void hideParentToFinishSession() throws Exception {
+ removeViewsBaseTest(
+ () -> mActivity.syncRunOnUiThread(() -> mParent.setVisibility(ViewGroup.INVISIBLE)),
+ null,
+ null,
+ "editText1", "editText2");
+ }
+
+ /**
+ * An activity that is currently getting autofilled might go into the background. While the
+ * tracked views are not visible on the screen anymore, this should not trigger a save.
+ */
+ public void activityToBackgroundShouldNotTriggerSave(@Nullable Runnable removeInBackGround,
+ @Nullable Runnable removeInForeGroup) throws Exception {
+ enableService();
+ try {
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE)
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, "editText1").build());
+
+ // Trigger autofill
+ eventually(() -> {
+ mActivity.syncRunOnUiThread(() -> mEditText2.requestFocus());
+ mActivity.syncRunOnUiThread(() -> mEditText1.requestFocus());
+
+ try {
+ sReplier.getNextFillRequest();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }, (int) (FILL_TIMEOUT_MS * 2));
+
+ sUiBot.assertNoDatasets();
+
+ mActivity.syncRunOnUiThread(() -> {
+ mEditText1.setText("editText1-filled");
+ mEditText2.setText("editText2-filled");
+ });
+
+ // Start activity on top
+ mActivity.startActivity(new Intent(getContext(),
+ ManualAuthenticationActivity.class));
+ mActivity.waitUntilStopped();
+
+ if (removeInBackGround != null) {
+ removeInBackGround.run();
+ }
+
+ sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+
+ // Remove previously started activity from top
+ sUiBot.selectById("android.autofillservice.cts:id/button");
+ mActivity.waitUntilResumed();
+
+ if (removeInForeGroup != null) {
+ sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+
+ removeInForeGroup.run();
+ }
+
+ // Save should be shows after all remove operations were executed
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+
+ SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertThat(findNodeByResourceId(saveRequest.structure, "editText1")
+ .getAutofillValue().getTextValue().toString()).isEqualTo("editText1-filled");
+ } finally {
+ disableService();
+ }
+ }
+
+ @Test
+ public void removeViewInBackground() throws Exception {
+ activityToBackgroundShouldNotTriggerSave(
+ () -> mActivity.syncRunOnUiThread(() -> {
+ // Do not trigger new partition when switching to editText2
+ mEditText2.setFocusable(false);
+
+ mParent.removeView(mEditText1);
+ }),
+ null);
+ }
+
+ @Test
+ public void hideViewInBackground() throws Exception {
+ activityToBackgroundShouldNotTriggerSave(
+ () -> mActivity.syncRunOnUiThread(() -> {
+ // Do not trigger new partition when switching to editText2
+ mEditText2.setFocusable(false);
+
+ mEditText1.setVisibility(ViewGroup.INVISIBLE);
+ }),
+ null);
+ }
+
+ @Test
+ public void hideParentInBackground() throws Exception {
+ activityToBackgroundShouldNotTriggerSave(
+ () -> mActivity.syncRunOnUiThread(() -> mParent.setVisibility(ViewGroup.INVISIBLE)),
+ null);
+ }
+
+ @Test
+ public void removeParentInBackground() throws Exception {
+ activityToBackgroundShouldNotTriggerSave(
+ () -> mActivity.syncRunOnUiThread(
+ () -> ((ViewGroup) mParent.getParent()).removeView(mParent)),
+ null);
+ }
+
+ @Test
+ public void removeViewAfterBackground() throws Exception {
+ activityToBackgroundShouldNotTriggerSave(
+ () -> mActivity.syncRunOnUiThread(() -> {
+ // Do not trigger new fill request when closing activity
+ mEditText1.setFocusable(false);
+ mEditText2.setFocusable(false);
+ }),
+ () -> mActivity.syncRunOnUiThread(() -> {
+ mParent.removeView(mEditText1);
+ }));
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index 2fa29ce..b4f5f06 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -66,6 +66,7 @@
private final String[] mAuthenticationIds;
private final CharSequence mNegativeActionLabel;
private final IntentSender mNegativeActionListener;
+ private final int mFlags;
private CannedFillResponse(Builder builder) {
mDatasets = builder.mDatasets;
@@ -79,6 +80,7 @@
mAuthenticationIds = builder.mAuthenticationIds;
mNegativeActionLabel = builder.mNegativeActionLabel;
mNegativeActionListener = builder.mNegativeActionListener;
+ mFlags = builder.mFlags;
}
/**
@@ -101,8 +103,17 @@
}
}
if (mRequiredSavableIds != null) {
- final SaveInfo.Builder saveInfo = new SaveInfo.Builder(mSaveType,
- getAutofillIds(structure, mRequiredSavableIds));
+ final SaveInfo.Builder saveInfo;
+
+ if (mRequiredSavableIds == null) {
+ saveInfo = new SaveInfo.Builder(mSaveType, null);
+ } else {
+ saveInfo = new SaveInfo.Builder(mSaveType,
+ getAutofillIds(structure, mRequiredSavableIds));
+ }
+
+ saveInfo.setFlags(mFlags);
+
if (mOptionalSavableIds != null) {
saveInfo.setOptionalIds(getAutofillIds(structure, mOptionalSavableIds));
}
@@ -126,6 +137,7 @@
return "CannedFillResponse: [datasets=" + mDatasets
+ ", requiredSavableIds=" + Arrays.toString(mRequiredSavableIds)
+ ", optionalSavableIds=" + Arrays.toString(mOptionalSavableIds)
+ + ", mFlags=" + mFlags
+ ", saveDescription=" + mSaveDescription
+ ", hasPresentation=" + (mPresentation != null)
+ ", hasAuthentication=" + (mAuthentication != null)
@@ -145,6 +157,7 @@
private String[] mAuthenticationIds;
private CharSequence mNegativeActionLabel;
private IntentSender mNegativeActionListener;
+ private int mFlags;
public Builder addDataset(CannedDataset dataset) {
mDatasets.add(dataset);
@@ -160,6 +173,11 @@
return this;
}
+ public Builder setFlags(int flags) {
+ mFlags = flags;
+ return this;
+ }
+
/**
* Sets the optional savable ids based on they {@code resourceId}.
*/
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index 7e8fa9c..7289b5a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -241,7 +241,7 @@
mActivity.onAddress((v) -> v.check(R.id.work_address));
mActivity.onSaveCc((v) -> v.setChecked(false));
mActivity.tapBuy();
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_CREDIT_CARD, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_CREDIT_CARD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
// Assert sanitization on save: everything should be available!
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerTestCase.java
index fb050c3..1d4f652 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerTestCase.java
@@ -90,7 +90,7 @@
activity.setDate(2010, 11, 12);
activity.tapOk();
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_GENERIC, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
assertWithMessage("onSave() not called").that(saveRequest).isNotNull();
diff --git a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/autofillservice/src/android/autofillservice/cts/DummyActivity.java
similarity index 69%
copy from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
copy to tests/autofillservice/src/android/autofillservice/cts/DummyActivity.java
index d599eba..a1f5bd9 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DummyActivity.java
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-package com.android.cts.webkit.renderprocesscrash;
+package android.autofillservice.cts;
import android.app.Activity;
import android.os.Bundle;
-import android.webkit.WebView;
+import android.widget.TextView;
-public class RenderProcessCrashActivity extends Activity {
-
+public class DummyActivity extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- WebView webView = new WebView(this);
- setContentView(webView);
- webView.loadUrl("chrome://kill");
+ TextView text = new TextView(this);
+ text.setText("foo");
+ setContentView(text);
}
}
diff --git a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/autofillservice/src/android/autofillservice/cts/EmptyActivity.java
similarity index 69%
copy from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
copy to tests/autofillservice/src/android/autofillservice/cts/EmptyActivity.java
index d599eba..1a64b8c 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/EmptyActivity.java
@@ -14,19 +14,20 @@
* limitations under the License.
*/
-package com.android.cts.webkit.renderprocesscrash;
+package android.autofillservice.cts;
+import android.support.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
-import android.webkit.WebView;
-public class RenderProcessCrashActivity extends Activity {
-
+/**
+ * Empty activity
+ */
+public class EmptyActivity extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- WebView webView = new WebView(this);
- setContentView(webView);
- webView.loadUrl("chrome://kill");
+
+ setContentView(R.layout.empty);
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FragmentContainerActivity.java b/tests/autofillservice/src/android/autofillservice/cts/FragmentContainerActivity.java
new file mode 100644
index 0000000..7be4496
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/FragmentContainerActivity.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Activity containing an fragment
+ */
+public class FragmentContainerActivity extends AbstractAutoFillActivity {
+ static final String FRAGMENT_TAG =
+ FragmentContainerActivity.class.getName() + "#FRAGMENT_TAG";
+ private CountDownLatch mResumed = new CountDownLatch(1);
+ private CountDownLatch mStopped = new CountDownLatch(0);
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.fragment_container);
+
+ // have to manually add fragment as we cannot remove it otherwise
+ getFragmentManager().beginTransaction().add(R.id.rootContainer,
+ new FragmentWithEditText(), FRAGMENT_TAG).commitNow();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ mStopped = new CountDownLatch(1);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ mResumed.countDown();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ mResumed = new CountDownLatch(1);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ mStopped.countDown();
+ }
+
+ public boolean waitUntilResumed() throws InterruptedException {
+ return mResumed.await(Helper.UI_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+
+ public boolean waitUntilStopped() throws InterruptedException {
+ return mStopped.await(Helper.UI_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FragmentWithEditText.java b/tests/autofillservice/src/android/autofillservice/cts/FragmentWithEditText.java
new file mode 100644
index 0000000..963daff
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/FragmentWithEditText.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import android.support.annotation.Nullable;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+/**
+ * A fragment with containing a single {@link EditText}
+ */
+public class FragmentWithEditText extends Fragment {
+ @Override
+ @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_with_edittext, null);
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
index 6df6f10..c9b6d30 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
@@ -113,7 +113,7 @@
onCell(row, column, (c) -> queue.offer(c.getText().toString()));
final String text = queue.poll(100, TimeUnit.MILLISECONDS);
if (text == null) {
- throw new AssertionError("text not set in 100ms");
+ throw new RetryableException("text not set in 100ms");
}
return text;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 37fb159..e19fa0c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -28,6 +28,7 @@
import android.os.UserManager;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
+import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -58,6 +59,12 @@
static final String ID_LOGIN = "login";
static final String ID_OUTPUT = "output";
+ /** Pass to {@link #setOrientation(int)} to change the display to portrait mode */
+ public static int PORTRAIT = 0;
+
+ /** Pass to {@link #setOrientation(int)} to change the display to landscape mode */
+ public static int LANDSCAPE = 1;
+
/**
* Timeout (in milliseconds) until framework binds / unbinds from service.
*/
@@ -88,6 +95,13 @@
*/
static final int RETRY_MS = 100;
+ private final static String ACCELLEROMETER_CHANGE =
+ "content insert --uri content://settings/system --bind name:s:accelerometer_rotation "
+ + "--bind value:i:%d";
+ private final static String ORIENTATION_CHANGE =
+ "content insert --uri content://settings/system --bind name:s:user_rotation --bind "
+ + "value:i:%d";
+
/**
* Runs a {@code r}, ignoring all {@link RuntimeException} and {@link Error} until the
* {@link #UI_TIMEOUT_MS} is reached.
@@ -338,7 +352,7 @@
final AutofillValue value = node.getAutofillValue();
assertWithMessage("null autofill value on %s", node).that(value).isNotNull();
assertWithMessage("wrong autofill type on %s", node).that(value.isText()).isTrue();
- assertWithMessage("wrong autofill value on %s", node).that(value.getTextValue())
+ assertWithMessage("wrong autofill value on %s", node).that(value.getTextValue().toString())
.isEqualTo(expectedText);
return node;
}
@@ -533,6 +547,56 @@
return requiredIds;
}
+ /**
+ * Prevents the screen to rotate by itself
+ */
+ public static void disableAutoRotation() {
+ runShellCommand(ACCELLEROMETER_CHANGE, 0);
+ setOrientation(PORTRAIT);
+ }
+
+ /**
+ * Allows the screen to rotate by itself
+ */
+ public static void allowAutoRotation() {
+ runShellCommand(ACCELLEROMETER_CHANGE, 1);
+ }
+
+ /**
+ * Changes the screen orientation. This triggers a activity lifecycle (destroy -> create) for
+ * activities that do not handle this config change such as {@link OutOfProcessLoginActivity}.
+ *
+ * @param value {@link #PORTRAIT} or {@link #LANDSCAPE};
+ */
+ public static void setOrientation(int value) {
+ runShellCommand(ORIENTATION_CHANGE, value);
+ }
+
+ /**
+ * Wait until a process starts and returns the process ID of the process.
+ *
+ * @return The pid of the process
+ */
+ public static int getOutOfProcessPid(@NonNull String processName) throws InterruptedException {
+ long startTime = System.currentTimeMillis();
+
+ while (System.currentTimeMillis() - startTime < UI_TIMEOUT_MS) {
+ String[] allProcessDescs = runShellCommand("ps -eo PID,ARGS=CMD").split("\n");
+
+ for (String processDesc : allProcessDescs) {
+ String[] pidAndName = processDesc.trim().split(" ");
+
+ if (pidAndName[1].equals(processName)) {
+ return Integer.parseInt(pidAndName[0]);
+ }
+ }
+
+ Thread.sleep(RETRY_MS);
+ }
+
+ throw new IllegalStateException("process not found");
+ }
+
private Helper() {
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index c78a6e1..bd69587 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -107,7 +107,7 @@
final String state = sConnectionStates.poll(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (state == null) {
dumpAutofillService();
- throw new AssertionError("not connected in " + CONNECTION_TIMEOUT_MS + " ms");
+ throw new RetryableException("not connected in %d ms", CONNECTION_TIMEOUT_MS);
}
assertWithMessage("Invalid connection state").that(state).isEqualTo(STATE_CONNECTED);
}
@@ -122,7 +122,7 @@
final String state = sConnectionStates.poll(2 * IDLE_UNBIND_TIMEOUT_MS,
TimeUnit.MILLISECONDS);
if (state == null) {
- throw new AssertionError("not disconnected in " + IDLE_UNBIND_TIMEOUT_MS + " ms");
+ throw new RetryableException("not disconnected in %d ms", IDLE_UNBIND_TIMEOUT_MS);
}
assertWithMessage("Invalid connection state").that(state).isEqualTo(STATE_DISCONNECTED);
}
@@ -221,8 +221,8 @@
FillRequest getNextFillRequest() throws InterruptedException {
final FillRequest request = mFillRequests.poll(FILL_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (request == null) {
- throw new AssertionError(
- "onFillRequest() not called in " + FILL_TIMEOUT_MS + " ms");
+ throw new RetryableException("onFillRequest() not called in %s ms",
+ FILL_TIMEOUT_MS);
}
return request;
}
@@ -245,8 +245,8 @@
SaveRequest getNextSaveRequest() throws InterruptedException {
final SaveRequest request = mSaveRequests.poll(SAVE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (request == null) {
- throw new AssertionError(
- "onSaveRequest() not called in " + SAVE_TIMEOUT_MS + " ms");
+ throw new RetryableException(
+ "onSaveRequest() not called in %d ms", SAVE_TIMEOUT_MS);
}
return request;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 3f68b50..635af0c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -39,7 +39,6 @@
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME;
import static android.text.InputType.TYPE_NULL;
import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
-import static android.view.View.AUTOFILL_MODE_MANUAL;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.autofill.AutofillManager.FLAG_MANUAL_REQUEST;
@@ -64,6 +63,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.autofill.AutofillManager;
+import android.widget.RemoteViews;
import org.junit.After;
import org.junit.Before;
@@ -181,7 +181,9 @@
@Override
public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
- info.addChild(v, virtualViewId);
+ if (virtualViewId == View.NO_ID) {
+ info.addChild(v, 108);
+ }
return info;
}
};
@@ -382,7 +384,7 @@
assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
// Assert the snack bar is shown and tap "Save".
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
@@ -795,7 +797,7 @@
assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
// Assert the snack bar is shown and tap "Save".
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
@@ -870,7 +872,7 @@
assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
// Assert the snack bar is shown and tap "Save".
- final UiObject2 saveSnackBar = sUiBot.assertSaveShowing(type, saveDescription);
+ final UiObject2 saveSnackBar = sUiBot.assertSaveShowing(saveDescription, type);
sUiBot.saveForAutofill(saveSnackBar, true);
// Assert save was called.
@@ -1095,53 +1097,18 @@
}
@Test
- public void testDisableSelfWhenConnected() throws Exception {
+ public void testDisableSelf() throws Exception {
enableService();
- // Set no-op behavior.
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
- .build());
-
- // Trigger auto-fill.
- mActivity.onUsername(View::requestFocus);
- waitUntilConnected();
- sReplier.getNextFillRequest();
-
// Can disable while connected.
- mActivity.runOnUiThread(() ->
- InstrumentedAutoFillService.peekInstance().disableSelf());
+ mActivity.runOnUiThread(() -> getContext().getSystemService(
+ AutofillManager.class).disableOwnedAutofillServices());
// Ensure disabled.
assertServiceDisabled();
}
@Test
- public void testDisableSelfWhenDisconnected() throws Exception {
- enableService();
-
- // Set no-op behavior.
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
- .build());
-
- // Trigger auto-fill.
- mActivity.onUsername(View::requestFocus);
- waitUntilConnected();
- sReplier.getNextFillRequest();
-
- // Wait until we timeout and disconnect.
- waitUntilDisconnected();
-
- // Cannot disable while disconnected.
- mActivity.runOnUiThread(() ->
- InstrumentedAutoFillService.peekInstance().disableSelf());
-
- // Ensure enabled.
- assertServiceEnabled();
- }
-
- @Test
public void testCustomNegativeSaveButton() throws Exception {
enableService();
@@ -1181,7 +1148,7 @@
}, intentFilter);
// Trigger the negative button.
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, false);
+ sUiBot.saveForAutofill(false, SAVE_DATA_TYPE_PASSWORD);
// Wait for the custom action.
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
@@ -1249,14 +1216,13 @@
assertThat(usernameContainer.getChildCount()).isEqualTo(2);
}
- @Test
public void testAutofillManuallyOneDataset() throws Exception {
// Set service.
enableService();
// And activity.
mActivity.onUsername((v) -> {
- v.setAutofillMode(AUTOFILL_MODE_MANUAL);
+ // v.setAutofillMode(AUTOFILL_MODE_MANUAL);
// TODO(b/33197203, b/33802548): setting an empty text, otherwise longPress() does not
// display the AUTOFILL context menu. Need to fix it, but it's a test case issue...
v.setText("");
@@ -1283,12 +1249,10 @@
mActivity.assertAutoFilled();
}
- @Test
public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
autofillManuallyTwoDatasets(true);
}
- @Test
public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
autofillManuallyTwoDatasets(false);
}
@@ -1299,7 +1263,7 @@
// And activity.
mActivity.onUsername((v) -> {
- v.setAutofillMode(AUTOFILL_MODE_MANUAL);
+ //v.setAutofillMode(AUTOFILL_MODE_MANUAL);
// TODO(b/33197203, b/33802548): setting an empty text, otherwise longPress() does not
// display the AUTOFILL context menu. Need to fix it, but it's a test case issue...
v.setText("");
@@ -1377,7 +1341,7 @@
mActivity.tapSave();
// Assert the snack bar is shown and tap "Save".
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
@@ -1493,4 +1457,47 @@
setUserRestrictionForAutofill(false);
}
}
+
+ @Test
+ public void testClickCustomButton() throws Exception {
+ // Set service.
+ enableService();
+
+ Intent intent = new Intent(getContext(), EmptyActivity.class);
+ IntentSender sender = PendingIntent.getActivity(getContext(), 0, intent,
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT)
+ .getIntentSender();
+
+ RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+ R.layout.list_item);
+ presentation.setTextViewText(R.id.text1, "Poke");
+ Intent firstIntent = new Intent(getContext(), DummyActivity.class);
+ presentation.setOnClickPendingIntent(R.id.text1, PendingIntent.getActivity(
+ getContext(), 0, firstIntent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_CANCEL_CURRENT));
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(sender)
+ .setPresentation(presentation)
+ .build());
+
+ // Trigger auto-fill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+
+ // Click on the custom button
+ sUiBot.selectByText("Poke");
+
+ // Make sure the click worked
+ sUiBot.selectByText("foo");
+
+ // Go back to the filled app.
+ sUiBot.pressBack();
+
+ // The session should be gone
+ assertNoDanglingSessions();
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
new file mode 100644
index 0000000..32844d4
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.Activity;
+import android.app.assist.AssistStructure;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.autofill.AutofillManager;
+
+/**
+ * An activity that authenticates on button press
+ */
+public class ManualAuthenticationActivity extends Activity {
+ private static CannedFillResponse sResponse;
+ private static CannedFillResponse.CannedDataset sDataset;
+
+ public static void setResponse(CannedFillResponse response) {
+ sResponse = response;
+ sDataset = null;
+ }
+
+ public static void setDataset(CannedFillResponse.CannedDataset dataset) {
+ sDataset = dataset;
+ sResponse = null;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.single_button_activity);
+
+ findViewById(R.id.button).setOnClickListener((v) -> {
+ AssistStructure structure = getIntent().getParcelableExtra(
+ AutofillManager.EXTRA_ASSIST_STRUCTURE);
+ if (structure != null) {
+ Parcelable result;
+ if (sResponse != null) {
+ result = sResponse.asFillResponse(structure);
+ } else if (sDataset != null) {
+ result = sDataset.asDataset(structure);
+ } else {
+ throw new IllegalStateException("no dataset or response");
+ }
+
+ // Pass on the auth result
+ Intent intent = new Intent();
+ intent.putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, result);
+ setResult(RESULT_OK, intent);
+ }
+
+ // Done
+ finish();
+ });
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java b/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java
index 13887fa..48b0c2f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java
@@ -50,7 +50,7 @@
MyEvent getEvent() throws InterruptedException {
final MyEvent event = mEvents.poll(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (event == null) {
- throw new AssertionError("no event in " + CONNECTION_TIMEOUT_MS + " ms");
+ throw new RetryableException("no event in %d ms", CONNECTION_TIMEOUT_MS);
}
return event;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
index 3b75868..16a633d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
@@ -130,7 +130,7 @@
mActivity.save();
// Assert the snack bar is shown and tap "Save".
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_ADDRESS, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_ADDRESS);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
assertWithMessage("onSave() not called").that(saveRequest).isNotNull();
@@ -330,7 +330,7 @@
mActivity.save();
// Assert the snack bar is shown and tap "Save".
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_ADDRESS, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_ADDRESS);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
assertWithMessage("onSave() not called").that(saveRequest).isNotNull();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OutOfProcessLoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/OutOfProcessLoginActivity.java
new file mode 100644
index 0000000..6dd2d11
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/OutOfProcessLoginActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Simple activity showing R.layout.login_activity. Started outside of the test process.
+ */
+public class OutOfProcessLoginActivity extends Activity {
+ private static final String LOG_TAG = OutOfProcessLoginActivity.class.getSimpleName();
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ Log.i(LOG_TAG, "onCreate(" + savedInstanceState + ")");
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.login_activity);
+
+ findViewById(R.id.login).setOnClickListener((v) -> {
+ finish();
+ });
+ }
+
+ @Override
+ protected void onStop() {
+ Log.i(LOG_TAG, "onStop()");
+ super.onStop();
+
+ try {
+ getStoppedMarker(this).createNewFile();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "cannot write stopped filed");
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.i(LOG_TAG, "onDestroy()");
+ super.onDestroy();
+ }
+
+ /**
+ * Get the file that signals that the activity has entered {@link Activity#onStop()}.
+ *
+ * @param context Context of the app
+ * @return The marker file that is written onStop()
+ */
+ @NonNull public static File getStoppedMarker(@NonNull Context context) {
+ return new File(context.getFilesDir(), "stopped");
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index 8c350aa5..49ddf8f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -25,7 +25,11 @@
import static android.autofillservice.cts.GridActivity.ID_L4C2;
import static android.autofillservice.cts.Helper.assertTextIsSanitized;
import static android.autofillservice.cts.Helper.assertValue;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -210,7 +214,6 @@
.setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
.setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
.build())
- .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
.setExtras(extras)
.build();
sReplier.addResponse(response1);
@@ -272,6 +275,7 @@
.setField(ID_L4C1, "l4c1", createPresentation("l4c1"))
.setField(ID_L4C2, "l4c2", createPresentation("l4c2"))
.build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
.setExtras(extras)
.build();
sReplier.addResponse(response4);
@@ -285,7 +289,7 @@
mActivity.setText(1, 1, "L1C1");
mActivity.save();
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
assertWithMessage("wrong number of extras on save request bundle")
@@ -293,6 +297,308 @@
assertThat(saveRequest.data.getString("numbers4")).isEqualTo("2342");
}
+ @Test
+ public void testSaveOneSaveInfoOnFirstPartitionWithIdsOnSecond() throws Exception {
+ // Set service.
+ enableService();
+
+ // Trigger 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .build();
+ sReplier.addResponse(response1);
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 2nd partition.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L2C1)
+ .build();
+ sReplier.addResponse(response2);
+ mActivity.focusCell(2, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger save
+ mActivity.setText(2, 1, "L2C1");
+ mActivity.save();
+
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertValue(saveRequest.structure, ID_L2C1, "L2C1");
+ }
+
+ @Test
+ public void testSaveOneSaveInfoOnSecondPartitionWithIdsOnFirst() throws Exception {
+ // Set service.
+ enableService();
+
+ // Trigger 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .build();
+ sReplier.addResponse(response1);
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 2nd partition.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
+ .build();
+ sReplier.addResponse(response2);
+ mActivity.focusCell(2, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger save
+ mActivity.setText(1, 1, "L1C1");
+ mActivity.save();
+
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertValue(saveRequest.structure, ID_L1C1, "L1C1");
+ }
+
+ @Test
+ public void testSaveTwoSaveInfosDifferentTypes() throws Exception {
+ // Set service.
+ enableService();
+
+ // Trigger 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
+ .build();
+ sReplier.addResponse(response1);
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 2nd partition.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_CREDIT_CARD,
+ ID_L2C1)
+ .build();
+ sReplier.addResponse(response2);
+ mActivity.focusCell(2, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger save
+ mActivity.setText(1, 1, "L1C1");
+ mActivity.setText(2, 1, "L2C1");
+ mActivity.save();
+
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD, SAVE_DATA_TYPE_CREDIT_CARD);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertValue(saveRequest.structure, ID_L1C1, "L1C1");
+ assertValue(saveRequest.structure, ID_L2C1, "L2C1");
+ }
+
+ @Test
+ public void testSaveThreeSaveInfosDifferentTypes() throws Exception {
+ // Set service.
+ enableService();
+
+ // Trigger 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
+ .build();
+ sReplier.addResponse(response1);
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 2nd partition.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_CREDIT_CARD,
+ ID_L2C1)
+ .build();
+ sReplier.addResponse(response2);
+ mActivity.focusCell(2, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 3rd partition.
+ final CannedFillResponse response3 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L3C1, "l3c1", createPresentation("l3c1"))
+ .setField(ID_L3C2, "l3c2", createPresentation("l3c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_CREDIT_CARD
+ | SAVE_DATA_TYPE_USERNAME, ID_L3C1)
+ .build();
+ sReplier.addResponse(response3);
+ mActivity.focusCell(3, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger save
+ mActivity.setText(1, 1, "L1C1");
+ mActivity.setText(2, 1, "L2C1");
+ mActivity.setText(3, 1, "L3C1");
+ mActivity.save();
+
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD, SAVE_DATA_TYPE_CREDIT_CARD,
+ SAVE_DATA_TYPE_USERNAME);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertValue(saveRequest.structure, ID_L1C1, "L1C1");
+ assertValue(saveRequest.structure, ID_L2C1, "L2C1");
+ assertValue(saveRequest.structure, ID_L3C1, "L3C1");
+ }
+
+ @Test
+ public void testSaveThreeSaveInfosDifferentTypesIncludingGeneric() throws Exception {
+ // Set service.
+ enableService();
+
+ // Trigger 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
+ .build();
+ sReplier.addResponse(response1);
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 2nd partition.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_GENERIC, ID_L2C1)
+ .build();
+ sReplier.addResponse(response2);
+ mActivity.focusCell(2, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 3rd partition.
+ final CannedFillResponse response3 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L3C1, "l3c1", createPresentation("l3c1"))
+ .setField(ID_L3C2, "l3c2", createPresentation("l3c2"))
+ .build())
+ .setRequiredSavableIds(
+ SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_GENERIC | SAVE_DATA_TYPE_USERNAME,
+ ID_L3C1)
+ .build();
+ sReplier.addResponse(response3);
+ mActivity.focusCell(3, 1);
+ sReplier.getNextFillRequest();
+
+
+ // Trigger save
+ mActivity.setText(1, 1, "L1C1");
+ mActivity.setText(2, 1, "L2C1");
+ mActivity.setText(3, 1, "L3C1");
+ mActivity.save();
+
+ // Make sure GENERIC type is not shown on snackbar
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD, SAVE_DATA_TYPE_USERNAME);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertValue(saveRequest.structure, ID_L1C1, "L1C1");
+ assertValue(saveRequest.structure, ID_L2C1, "L2C1");
+ assertValue(saveRequest.structure, ID_L3C1, "L3C1");
+ }
+
+ @Test
+ public void testSaveMoreThanThreeSaveInfosDifferentTypes() throws Exception {
+ // Set service.
+ enableService();
+
+ // Trigger 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
+ .build();
+ sReplier.addResponse(response1);
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 2nd partition.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_CREDIT_CARD,
+ ID_L2C1)
+ .build();
+ sReplier.addResponse(response2);
+ mActivity.focusCell(2, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 3rd partition.
+ final CannedFillResponse response3 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L3C1, "l3c1", createPresentation("l3c1"))
+ .setField(ID_L3C2, "l3c2", createPresentation("l3c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_CREDIT_CARD
+ | SAVE_DATA_TYPE_USERNAME, ID_L3C1)
+ .build();
+ sReplier.addResponse(response3);
+ mActivity.focusCell(3, 1);
+ sReplier.getNextFillRequest();
+
+ // Trigger 4th partition.
+ final CannedFillResponse response4 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L4C1, "l4c1", createPresentation("l4c1"))
+ .setField(ID_L4C2, "l4c2", createPresentation("l4c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD | SAVE_DATA_TYPE_CREDIT_CARD
+ | SAVE_DATA_TYPE_USERNAME | SAVE_DATA_TYPE_ADDRESS, ID_L4C1)
+ .build();
+ sReplier.addResponse(response4);
+ mActivity.focusCell(4, 1);
+ sReplier.getNextFillRequest();
+
+
+ // Trigger save
+ mActivity.setText(1, 1, "L1C1");
+ mActivity.setText(2, 1, "L2C1");
+ mActivity.setText(3, 1, "L3C1");
+ mActivity.setText(4, 1, "L4C1");
+ mActivity.save();
+
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertValue(saveRequest.structure, ID_L1C1, "L1C1");
+ assertValue(saveRequest.structure, ID_L2C1, "L2C1");
+ assertValue(saveRequest.structure, ID_L3C1, "L3C1");
+ assertValue(saveRequest.structure, ID_L4C1, "L4C1");
+ }
+
// TODO(b/33197203, b/35707731): test force autofill after autofilled
- // TODO(b/33197203, b/35707731): add test for saving (1, 2, 3, or more unique save types)
+ // TODO(b/33197203, b/35707731): test save with different subtitles and custom no button
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
index f0e8f9f..349149f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
@@ -93,7 +93,7 @@
mActivity.tapLogin();
// Assert the snack bar is shown and tap "Save".
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
// Assert sanitization on save: everything should be available!
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java b/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
new file mode 100644
index 0000000..a4db0f4
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import android.util.Log;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Custom JUnit4 rule that retry tests when they fail due to a {@link RetryableException}.
+ */
+public class RetryRule implements TestRule {
+
+ private static final String TAG = "RetryRule";
+ private final int mMaxAttempts;
+
+ public RetryRule(int maxAttempts) {
+ if (maxAttempts < 2) {
+ throw new IllegalArgumentException(
+ "Must retry at least once; otherwise, what's the point?");
+ }
+ mMaxAttempts = maxAttempts;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ RetryableException caught = null;
+ for (int i = 1; i <= mMaxAttempts; i++) {
+ try {
+ base.evaluate();
+ return;
+ } catch (RetryableException e) {
+ caught = e;
+ Log.w(TAG,
+ description.getDisplayName() + ": attempt " + i + " failed: " + e);
+ }
+ }
+ throw caught;
+ }
+ };
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryRuleTest.java b/tests/autofillservice/src/android/autofillservice/cts/RetryRuleTest.java
new file mode 100644
index 0000000..50ae8c8
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryRuleTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+@RunWith(AndroidJUnit4.class)
+public class RetryRuleTest {
+
+ private final Description mDescription = Description.createSuiteDescription("Whatever");
+
+ private static final RetryableException sRetryableException =
+ new RetryableException("Y U NO RETRY?");
+
+ private static class RetryableStatement extends Statement {
+ private final int mNumberFailures;
+ private int mNumberCalls;
+
+ RetryableStatement(int numberFailures) {
+ mNumberFailures = numberFailures;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ mNumberCalls ++;
+ if (mNumberCalls <= mNumberFailures) {
+ throw sRetryableException;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "RetryableStatement: failures=" + mNumberFailures + ", calls=" + mNumberCalls;
+ }
+ }
+
+ @Test
+ public void testPass() throws Throwable {
+ final RetryRule rule = new RetryRule(2);
+ rule.apply(new RetryableStatement(1), mDescription).evaluate();
+ }
+
+ @Test
+ public void testFail() throws Throwable {
+ final RetryRule rule = new RetryRule(2);
+ try {
+ rule.apply(new RetryableStatement(2), mDescription).evaluate();
+ throw new AssertionError("2ND CALL, Y U NO FAIL?");
+ } catch (RetryableException e) {
+ assertThat(e).isSameAs(sRetryableException);
+ }
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryableException.java b/tests/autofillservice/src/android/autofillservice/cts/RetryableException.java
new file mode 100644
index 0000000..9b9d651
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryableException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+/**
+ * Exception that cause the {@link RetryRule} to re-try a test.
+ */
+public class RetryableException extends RuntimeException {
+
+ public RetryableException(String msg) {
+ super(msg);
+ }
+
+ public RetryableException(String format, Object...args) {
+ this(String.format(format, args));
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
new file mode 100644
index 0000000..0454277
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2017 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.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.ID_LOGIN;
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.LANDSCAPE;
+import static android.autofillservice.cts.Helper.PORTRAIT;
+import static android.autofillservice.cts.Helper.assertTextAndValue;
+import static android.autofillservice.cts.Helper.eventually;
+import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getOutOfProcessPid;
+import static android.autofillservice.cts.Helper.runShellCommand;
+import static android.autofillservice.cts.Helper.setOrientation;
+import static android.autofillservice.cts.OutOfProcessLoginActivity.getStoppedMarker;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.PendingIntent;
+import android.app.assist.AssistStructure;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.support.test.rule.ActivityTestRule;
+import android.view.autofill.AutofillValue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test the lifecycle of a autofill session
+ */
+public class SessionLifecycleTest extends AutoFillServiceTestCase {
+ private static final String USERNAME_FULL_ID = "android.autofillservice.cts:id/" + ID_USERNAME;
+ private static final String PASSWORD_FULL_ID = "android.autofillservice.cts:id/" + ID_PASSWORD;
+ private static final String LOGIN_FULL_ID = "android.autofillservice.cts:id/" + ID_LOGIN;
+ private static final String BUTTON_FULL_ID = "android.autofillservice.cts:id/button";
+
+ /**
+ * Use an activity as background so that orientation change always works (Home screen does not
+ * allow rotation
+ */
+ @Rule
+ public final ActivityTestRule<EmptyActivity> mActivityRule =
+ new ActivityTestRule<>(EmptyActivity.class);
+
+ @Before
+ public void removeAllSessions() {
+ destroyAllSessions();
+ }
+
+ /**
+ * Prevents the screen to rotate by itself
+ */
+ @Before
+ public void disableAutoRotation() {
+ Helper.disableAutoRotation();
+ }
+
+ /**
+ * Allows the screen to rotate by itself
+ */
+ @After
+ public void allowAutoRotation() {
+ Helper.allowAutoRotation();
+ }
+
+ @Test
+ public void testSessionRetainedWhileAutofilledAppIsLifecycled() throws Exception {
+ // Set service.
+ enableService();
+
+ try {
+ // Start activity that is autofilled in a separate process so it can be killed
+ Intent outOfProcessAcvitityStartIntent = new Intent(getContext(),
+ OutOfProcessLoginActivity.class);
+ getContext().startActivity(outOfProcessAcvitityStartIntent);
+
+ // Set expectations.
+ final Bundle extras = new Bundle();
+ extras.putString("numbers", "4815162342");
+
+ // Create the authentication intent (launching a full screen activity)
+ IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), ManualAuthenticationActivity.class),
+ 0).getIntentSender();
+
+ // Prepare the authenticated response
+ ManualAuthenticationActivity.setResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_USERNAME, AutofillValue.forText("autofilled username"))
+ .setPresentation(createPresentation("dataset")).build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+ .setExtras(extras).build());
+
+ CannedFillResponse response = new CannedFillResponse.Builder()
+ .setAuthentication(authentication)
+ .setPresentation(createPresentation("authenticate"))
+ .build();
+ sReplier.addResponse(response);
+
+ // Trigger autofill on username
+ sUiBot.selectById(USERNAME_FULL_ID);
+
+ // Wait for fill request to be processed
+ sReplier.getNextFillRequest();
+
+ // Wait until authentication is shown
+ sUiBot.assertShownByText("authenticate");
+
+ // Change orientation which triggers a destroy -> create in the app as the activity
+ // cannot deal with such situations
+ setOrientation(LANDSCAPE);
+
+ // Delete stopped marker
+ getStoppedMarker(getContext()).delete();
+
+ // Authenticate
+ sUiBot.selectByText("authenticate");
+
+ // Waiting for activity to stop (stop marker appears)
+ eventually(() -> assertThat(getStoppedMarker(getContext()).exists()).isTrue());
+
+ // onStop might not be finished, hence wait more
+ Thread.sleep(1000);
+
+ // Kill activity that is in the background
+ runShellCommand("kill -9 %d",
+ getOutOfProcessPid("android.autofillservice.cts.outside"));
+
+ // Change orientation which triggers a destroy -> create in the app as the activity
+ // cannot deal with such situations
+ setOrientation(PORTRAIT);
+
+ // Approve authentication
+ sUiBot.selectById(BUTTON_FULL_ID);
+
+ // Wait for dataset to be shown
+ sUiBot.assertShownByText("dataset");
+
+ // Change orientation which triggers a destroy -> create in the app as the activity
+ // cannot deal with such situations
+ setOrientation(LANDSCAPE);
+
+ // Select dataset
+ sUiBot.selectDataset("dataset");
+
+ // Check the results.
+ eventually(() -> assertThat(sUiBot.getTextById(USERNAME_FULL_ID)).isEqualTo(
+ "autofilled username"));
+
+ // Set password
+ sUiBot.setTextById(PASSWORD_FULL_ID, "new password");
+
+ // Login
+ sUiBot.selectById(LOGIN_FULL_ID);
+
+ // Wait for save UI to be shown
+ sUiBot.assertShownById("android:id/autofill_save_yes");
+
+ // Change orientation to make sure save UI can handle this
+ setOrientation(PORTRAIT);
+
+ // Tap "Save".
+ sUiBot.selectById("android:id/autofill_save_yes");
+
+ // Get save request
+ InstrumentedAutoFillService.SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertWithMessage("onSave() not called").that(saveRequest).isNotNull();
+
+ // Make sure data is correctly saved
+ final AssistStructure.ViewNode username = findNodeByResourceId(saveRequest.structure,
+ ID_USERNAME);
+ assertTextAndValue(username, "autofilled username");
+ final AssistStructure.ViewNode password = findNodeByResourceId(saveRequest.structure,
+ ID_PASSWORD);
+ assertTextAndValue(password, "new password");
+
+ // Make sure extras were passed back on onSave()
+ assertThat(saveRequest.data).isNotNull();
+ final String extraValue = saveRequest.data.getString("numbers");
+ assertWithMessage("extras not passed on save").that(extraValue).isEqualTo("4815162342");
+
+ eventually(() -> assertNoDanglingSessions());
+ } finally {
+ disableService();
+ }
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerTestCase.java
index 872ccc1..b96e5e3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerTestCase.java
@@ -89,7 +89,7 @@
activity.setTime(10, 40);
activity.tapOk();
- sUiBot.saveForAutofill(SAVE_DATA_TYPE_GENERIC, true);
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
assertWithMessage("onSave() not called").that(saveRequest).isNotNull();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index be9b44b..deba8b7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -39,6 +39,7 @@
import android.util.Log;
import android.view.accessibility.AccessibilityWindowInfo;
+import java.util.Arrays;
import java.util.List;
/**
@@ -59,7 +60,7 @@
private static final String RESOURCE_STRING_SAVE_TYPE_CREDIT_CARD =
"autofill_save_type_credit_card";
private static final String RESOURCE_STRING_SAVE_TYPE_USERNAME = "autofill_save_type_username";
- private static final String RESOURCE_STRING_SAVE_TYPE_EMAIL =
+ private static final String RESOURCE_STRING_SAVE_TYPE_EMAIL_ADDRESS =
"autofill_save_type_email_address";
private static final String RESOURCE_STRING_AUTOFILL = "autofill";
private static final String RESOURCE_STRING_DATASET_PICKER_ACCESSIBILITY_TITLE =
@@ -91,7 +92,7 @@
// not showing...
return;
}
- throw new AssertionError("floating ui is shown: " + ui);
+ throw new RetryableException("floating ui is shown: %s", ui);
}
/**
@@ -161,10 +162,50 @@
}
/**
+ * Selects a view by id.
+ */
+ void selectById(String id) {
+ Log.v(TAG, "selectById(): " + id);
+
+ final UiObject2 view = waitForObject(By.res(id));
+ view.click();
+ }
+
+ /**
+ * Asserts the id is shown on the screen.
+ */
+ void assertShownById(String id) {
+ assertThat(waitForObject(By.res(id))).isNotNull();
+ }
+
+ /**
+ * Gets the text set on a view.
+ */
+ String getTextById(String id) {
+ UiObject2 view = waitForObject(By.res(id));
+ return view.getText();
+ }
+
+ /**
+ * Sets a new text on a view.
+ */
+ void setTextById(String id, String newText) {
+ UiObject2 view = waitForObject(By.res(id));
+ view.setText(newText);
+ }
+
+ /**
* Asserts the save snackbar is showing and returns it.
*/
UiObject2 assertSaveShowing(int type) {
- return assertSaveShowing(type, null);
+ return assertSaveShowing(null, type);
+ }
+
+ /**
+ * Presses the back button.
+ */
+ void pressBack() {
+ mDevice.pressBack();
}
/**
@@ -178,49 +219,66 @@
// not showing (in which case it wouldn't need a type as parameter).
return;
}
- throw new AssertionError("snack bar is showing");
+ throw new RetryableException("snack bar is showing");
}
- UiObject2 assertSaveShowing(int type, String description) {
+ private String getSaveTypeString(int type) {
+ final String typeResourceName;
+ switch (type) {
+ case SAVE_DATA_TYPE_PASSWORD:
+ typeResourceName = RESOURCE_STRING_SAVE_TYPE_PASSWORD;
+ break;
+ case SAVE_DATA_TYPE_ADDRESS:
+ typeResourceName = RESOURCE_STRING_SAVE_TYPE_ADDRESS;
+ break;
+ case SAVE_DATA_TYPE_CREDIT_CARD:
+ typeResourceName = RESOURCE_STRING_SAVE_TYPE_CREDIT_CARD;
+ break;
+ case SAVE_DATA_TYPE_USERNAME:
+ typeResourceName = RESOURCE_STRING_SAVE_TYPE_USERNAME;
+ break;
+ case SAVE_DATA_TYPE_EMAIL_ADDRESS:
+ typeResourceName = RESOURCE_STRING_SAVE_TYPE_EMAIL_ADDRESS;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported type: " + type);
+ }
+ return getString(typeResourceName);
+ }
+
+ UiObject2 assertSaveShowing(String description, int... types) {
final UiObject2 snackbar = waitForObject(By.res("android", RESOURCE_ID_SAVE_SNACKBAR),
SAVE_TIMEOUT_MS);
final UiObject2 titleView = snackbar.findObject(By.res("android", RESOURCE_ID_SAVE_TITLE));
assertWithMessage("save title (%s)", RESOURCE_ID_SAVE_TITLE).that(titleView).isNotNull();
- final String serviceLabel = InstrumentedAutoFillService.class.getSimpleName();
- final String expectedTitle;
- if (type == SAVE_DATA_TYPE_GENERIC) {
- expectedTitle = getString(RESOURCE_STRING_SAVE_TITLE, serviceLabel);
- } else {
- final String typeResourceName;
- switch (type) {
- case SAVE_DATA_TYPE_PASSWORD:
- typeResourceName = RESOURCE_STRING_SAVE_TYPE_PASSWORD;
- break;
- case SAVE_DATA_TYPE_ADDRESS:
- typeResourceName = RESOURCE_STRING_SAVE_TYPE_ADDRESS;
- break;
- case SAVE_DATA_TYPE_CREDIT_CARD:
- typeResourceName = RESOURCE_STRING_SAVE_TYPE_CREDIT_CARD;
- break;
- case SAVE_DATA_TYPE_USERNAME:
- typeResourceName = RESOURCE_STRING_SAVE_TYPE_USERNAME;
- break;
- case SAVE_DATA_TYPE_EMAIL_ADDRESS:
- typeResourceName = RESOURCE_STRING_SAVE_TYPE_EMAIL;
- break;
- default:
- throw new IllegalArgumentException("Unsupported type: " + type);
- }
- final String typeString = getString(typeResourceName);
- expectedTitle = getString(RESOURCE_STRING_SAVE_TITLE_WITH_TYPE, typeString,
- serviceLabel);
- }
-
final String actualTitle = titleView.getText();
Log.d(TAG, "save title: " + actualTitle);
- assertThat(actualTitle).isEqualTo(expectedTitle);
+
+ final String serviceLabel = InstrumentedAutoFillService.class.getSimpleName();
+ switch (types.length) {
+ case 1:
+ final String expectedTitle = (types[0] == SAVE_DATA_TYPE_GENERIC)
+ ? getString(RESOURCE_STRING_SAVE_TITLE, serviceLabel)
+ : getString(RESOURCE_STRING_SAVE_TITLE_WITH_TYPE,
+ getSaveTypeString(types[0]), serviceLabel);
+ assertThat(actualTitle).isEqualTo(expectedTitle);
+ break;
+ case 2:
+ // We cannot predict the order...
+ assertThat(actualTitle).contains(getSaveTypeString(types[0]));
+ assertThat(actualTitle).contains(getSaveTypeString(types[1]));
+ break;
+ case 3:
+ // We cannot predict the order...
+ assertThat(actualTitle).contains(getSaveTypeString(types[0]));
+ assertThat(actualTitle).contains(getSaveTypeString(types[1]));
+ assertThat(actualTitle).contains(getSaveTypeString(types[2]));
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid types: " + Arrays.toString(types));
+ }
if (description != null) {
final UiObject2 saveSubTitle = snackbar.findObject(By.text(description));
@@ -233,11 +291,11 @@
/**
* Taps an option in the save snackbar.
*
- * @param type expected type of save info.
* @param yesDoIt {@code true} for 'YES', {@code false} for 'NO THANKS'.
+ * @param types expected types of save info.
*/
- void saveForAutofill(int type, boolean yesDoIt) {
- final UiObject2 saveSnackBar = assertSaveShowing(type, null);
+ void saveForAutofill(boolean yesDoIt, int... types) {
+ final UiObject2 saveSnackBar = assertSaveShowing(null, types);
saveForAutofill(saveSnackBar, yesDoIt);
}
@@ -277,7 +335,7 @@
}
menuNames.append("'").append(menuName).append("' ");
}
- throw new AssertionError("no '" + expectedText + "' on " + menuNames);
+ throw new RetryableException("no '%s' on '%s'", expectedText, menuNames);
}
/**
@@ -324,8 +382,8 @@
}
SystemClock.sleep(napTime);
}
- throw new AssertionError("Object with selector " + selector + " not found in "
- + mTimeout + " ms");
+ throw new RetryableException("Object with selector '%s' not found in %d ms",
+ selector, mTimeout);
}
/**
@@ -354,9 +412,10 @@
}
SystemClock.sleep(napTime);
}
- throw new AssertionError("Objects with selector " + selector + " not found in "
- + mTimeout + " ms");
+ throw new RetryableException("Objects with selector '%s' not found in %d ms",
+ selector, mTimeout);
}
+
private UiObject2 findDatasetPicker() {
final UiObject2 picker = waitForObject(By.res("android", RESOURCE_ID_DATASET_PICKER));
@@ -378,6 +437,6 @@
return;
}
}
- throw new AssertionError("Title (" + expectedTitle + ") not found for " + object);
+ throw new RetryableException("Title '%s' not found for %s", expectedTitle, object);
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index 54b474e..763c57f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -18,16 +18,9 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.testng.Assert.assertThrows;
-
-import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
-import android.support.annotation.NonNull;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import org.junit.Before;
import org.junit.Rule;
@@ -41,227 +34,10 @@
new ActivityTestRule<>(ViewAttributesTestActivity.class);
private ViewAttributesTestActivity mActivity;
- private EditText mFirstLevelDefault;
- private EditText mFirstLevelManual;
- private EditText mFirstLevelAuto;
- private EditText mFirstLevelInherit;
- private EditText mManualContainerInherit;
- private EditText mManualContainerDefault;
- private EditText mManualContainerManual;
- private EditText mManualContainerAuto;
- private OneTimeTextWatcher mFirstLevelDefaultTextWatcher;
@Before
public void setActivity() {
mActivity = mActivityRule.getActivity();
- mFirstLevelDefault = (EditText) mActivity.findViewById(R.id.firstLevelDefault);
- mFirstLevelManual = (EditText) mActivity.findViewById(R.id.firstLevelManual);
- mFirstLevelAuto = (EditText) mActivity.findViewById(R.id.firstLevelAuto);
- mFirstLevelInherit = (EditText) mActivity.findViewById(R.id.firstLevelInherit);
- mManualContainerDefault = (EditText) mActivity.findViewById(R.id.manualContainerDefault);
- mManualContainerManual = (EditText) mActivity.findViewById(R.id.manualContainerManual);
- mManualContainerAuto = (EditText) mActivity.findViewById(R.id.manualContainerAuto);
- mManualContainerInherit = (EditText) mActivity.findViewById(R.id.manualContainerInherit);
- }
-
- private void runOnUiThreadSync(@NonNull Runnable r) throws InterruptedException {
- RuntimeException exceptionOnUiThread[] = {null};
-
- synchronized (this) {
- mActivity.runOnUiThread(() -> {
- synchronized (this) {
- try {
- r.run();
- } catch (RuntimeException e) {
- exceptionOnUiThread[0] = e;
- }
- this.notify();
- }
- });
-
- wait();
- }
-
- if (exceptionOnUiThread[0] != null) {
- throw exceptionOnUiThread[0];
- }
- }
-
- /**
- * Sets the expectation for an auto-fill request, so it can be asserted through
- * {@link #assertAutoFilled()} later.
- */
- void expectAutoFill() {
- mFirstLevelDefaultTextWatcher = new OneTimeTextWatcher("firstLevelDefault",
- mFirstLevelDefault, "filled");
- mFirstLevelDefault.addTextChangedListener(mFirstLevelDefaultTextWatcher);
- }
-
- /**
- * Asserts the activity was auto-filled with the values passed to
- * {@link #expectAutoFill()}.
- */
- void assertAutoFilled() throws Exception {
- mFirstLevelDefaultTextWatcher.assertAutoFilled();
- }
-
- /**
- * Try to auto-fill by moving the focus to {@code field}. If the field should trigger an
- * auto-fill the auto-fill UI should show up.
- *
- * @param field The field to move the focus to
- * @param expectUI If the auto-fill UI is expected to show up
- *
- * @throws Exception If something unexpected happened
- */
- private void checkFieldBehavior(@NonNull EditText field, boolean expectUI) throws Exception {
- if (expectUI) {
- assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
- } else {
- assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
- }
-
- // Make sure the requestFocus triggers a change
- if (field == mFirstLevelManual) {
- runOnUiThreadSync(() -> mFirstLevelDefault.requestFocus());
- } else {
- runOnUiThreadSync(() -> mFirstLevelManual.requestFocus());
- }
-
- enableService();
-
- try {
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedFillResponse.CannedDataset.Builder()
- .setField("firstLevelDefault", "filled")
- .setField("firstLevelManual", "filled")
- .setField("firstLevelAuto", "filled")
- .setField("firstLevelInherit", "filled")
- .setField("manualContainerDefault", "filled")
- .setField("manualContainerManual", "filled")
- .setField("manualContainerAuto", "filled")
- .setField("manualContainerInherit", "filled")
- .setPresentation(createPresentation("dataset"))
- .build())
- .build());
-
- expectAutoFill();
-
- runOnUiThreadSync(() -> field.requestFocus());
-
- Throwable exceptionDuringAutoFillTrigger = null;
- try {
- sReplier.getNextFillRequest();
- sUiBot.selectDataset("dataset");
- } catch (Throwable e) {
- if (expectUI) {
- throw e;
- } else {
- exceptionDuringAutoFillTrigger = e;
- }
- }
-
- if (expectUI) {
- assertAutoFilled();
- } else {
- assertThat(exceptionDuringAutoFillTrigger).isNotNull();
- }
- } finally {
- disableService();
- }
- }
-
- @Test
- public void checkDefaultValue() {
- assertThat(mFirstLevelDefault.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
- }
-
- @Test
- public void checkInheritValue() {
- assertThat(mFirstLevelInherit.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
- }
-
- @Test
- public void checkAutoValue() {
- assertThat(mFirstLevelAuto.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
- }
-
- @Test
- public void checkManualValue() {
- assertThat(mFirstLevelManual.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
- }
-
- @Test
- public void checkNestedDefaultValue() {
- assertThat(mManualContainerDefault.getAutofillMode()).isEqualTo(
- View.AUTOFILL_MODE_INHERIT);
- }
-
- @Test
- public void checkNestedInheritValue() {
- assertThat(mManualContainerInherit.getAutofillMode()).isEqualTo(
- View.AUTOFILL_MODE_INHERIT);
- }
-
- @Test
- public void checkNestedAutoValue() {
- assertThat(mManualContainerAuto.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
- }
-
- @Test
- public void checkNestedManualValue() {
- assertThat(mManualContainerManual.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
- }
-
- @Test
- public void checkDefaultBehavior() throws Exception {
- checkFieldBehavior(mFirstLevelDefault, true);
- }
-
- @Test
- public void checkInheritBehavior() throws Exception {
- checkFieldBehavior(mFirstLevelInherit, true);
- }
-
- @Test
- public void checkAutoBehavior() throws Exception {
- checkFieldBehavior(mFirstLevelAuto, true);
- }
-
- @Test
- public void checkManualBehavior() throws Exception {
- checkFieldBehavior(mFirstLevelManual, false);
- }
-
- @Test
- public void checkNestedDefaultBehavior() throws Exception {
- checkFieldBehavior(mManualContainerDefault, false);
- }
-
- @Test
- public void checkNestedInheritBehavior() throws Exception {
- checkFieldBehavior(mManualContainerInherit, false);
- }
-
- @Test
- public void checkNestedAutoBehavior() throws Exception {
- checkFieldBehavior(mManualContainerAuto, true);
- }
-
- @Test
- public void checkNestedManualBehavior() throws Exception {
- checkFieldBehavior(mManualContainerManual, false);
- }
-
- @Test
- public void checksetAutofillMode() {
- mFirstLevelDefault.setAutofillMode(View.AUTOFILL_MODE_MANUAL);
- assertThat(mFirstLevelDefault.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
- }
-
- @Test
- public void checkIllegalAutoFillModeSet() throws Exception {
- assertThrows(IllegalArgumentException.class, () -> mFirstLevelDefault.setAutofillMode(-1));
}
@Test
@@ -317,85 +93,4 @@
assertThat(v.getAutofillHints()).isEqualTo(new String[]{View.AUTOFILL_HINT_PASSWORD,
View.AUTOFILL_HINT_EMAIL_ADDRESS});
}
-
- @Test
- public void attachViewToManualContainer() throws Exception {
- runOnUiThreadSync(() -> mFirstLevelManual.requestFocus());
- enableService();
-
- try {
- View view = new TextView(mActivity);
-
- view.setLayoutParams(
- new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
-
- assertThat(view.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
- assertThat(view.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-
- // Requesting focus should not trigger any mishaps
- runOnUiThreadSync(() -> view.requestFocus());
-
- LinearLayout attachmentPoint = (LinearLayout) mActivity.findViewById(
- R.id.manualContainer);
- runOnUiThreadSync(() -> attachmentPoint.addView(view));
-
- assertThat(view.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
- } finally {
- disableService();
- }
- }
-
- @Test
- public void attachNestedViewToContainer() throws Exception {
- runOnUiThreadSync(() -> mFirstLevelManual.requestFocus());
- enableService();
-
- try {
- // Create view and viewGroup but do not attach to window
- LinearLayout container = (LinearLayout) mActivity.getLayoutInflater().inflate(
- R.layout.nested_layout, null);
- EditText field = container.findViewById(R.id.field);
-
- assertThat(field.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
- assertThat(container.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
-
- // Resolved mode for detached views should behave as documented
- assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
- assertThat(container.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-
- // Requesting focus should not trigger any mishaps
- runOnUiThreadSync(() -> field.requestFocus());
-
- // Set up auto-fill service and response
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedFillResponse.CannedDataset.Builder()
- .setField("field", "filled")
- .setPresentation(createPresentation("dataset"))
- .build())
- .build());
-
- OneTimeTextWatcher mViewWatcher = new OneTimeTextWatcher("field", field, "filled");
- field.addTextChangedListener(mViewWatcher);
-
- // As the focus is set to "field", attaching "container" should trigger an auto-fill
- // request on "field"
- LinearLayout attachmentPoint = (LinearLayout) mActivity.findViewById(
- R.id.rootContainer);
- runOnUiThreadSync(() -> attachmentPoint.addView(container));
-
- // Now the resolved auto-fill modes make sense, hence check them
- assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
- assertThat(container.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-
- // We should now be able to select the data set
- sReplier.getNextFillRequest();
- sUiBot.selectDataset("dataset");
-
- // Check if auto-fill operation worked
- mViewWatcher.assertAutoFilled();
- } finally {
- disableService();
- }
- }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index 6b97195..0344830 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -127,7 +127,7 @@
try {
VirtualContainerView.assertHtmlInfo(username);
VirtualContainerView.assertHtmlInfo(password);
- } catch (AssertionError e) {
+ } catch (AssertionError | RuntimeException e) {
dumpStructure("HtmlInfo failed", request.structure);
throw e;
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 6ae3011..b51e338 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -1649,10 +1649,6 @@
checkMeteringRect(afRegions);
}
}
- // ZSL must default to OFF
- if (request.get(CONTROL_ENABLE_ZSL) != null) {
- mCollector.expectKeyValueEquals(request, CONTROL_ENABLE_ZSL, false);
- }
}
// Sensor settings.
@@ -1915,6 +1911,13 @@
}
}
+ // Enable ZSL
+ if (template != CameraDevice.TEMPLATE_STILL_CAPTURE) {
+ if (mStaticInfo.areKeysAvailable(CONTROL_ENABLE_ZSL)) {
+ mCollector.expectKeyValueEquals(request, CONTROL_ENABLE_ZSL, false);
+ }
+ }
+
int[] outputFormats = mStaticInfo.getAvailableFormats(
StaticMetadata.StreamDirection.Output);
boolean supportRaw = false;
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index 6c48418..e011131 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -1262,7 +1262,11 @@
private long getExposureValue(CaptureResult result) throws Exception {
int expTimeUs = (int) (getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000);
int sensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
- return expTimeUs * sensitivity;
+ Integer postRawSensitivity = result.get(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST);
+ if (postRawSensitivity != null) {
+ return (long) sensitivity * postRawSensitivity / 100 * expTimeUs;
+ }
+ return (long) sensitivity * expTimeUs;
}
private long getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs,
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 6bb3421..655621c 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -240,6 +240,16 @@
bug: 23827982
},
{
+ description: "VP9 encoder is not a standard requirement of android as of O.",
+ names: [
+ "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180",
+ "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360",
+ "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720",
+ "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080"
+ ],
+ bug: 33090965
+},
+{
description: "protected broadcast not working",
names: [
"android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
@@ -286,5 +296,12 @@
"android.telecom.cts.WiredHeadsetTest"
],
bug: 26149528
+},
+{
+ desciption: "Seems to be failing on X86, flaky on arm. Root cause to be investigated",
+ names: [
+ "android.webkit.cts.WebViewClientTest#testOnRenderProcessGone"
+ ],
+ bug: 37281280
}
]
diff --git a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
index b5e9cad..f234155 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -59,11 +59,8 @@
public ActivityTestRule<FragmentTestActivity> mActivityRule =
new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
- private Instrumentation mInstrumentation;
-
@Before
public void setupContainer() {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
}
@@ -365,12 +362,12 @@
.replace(R.id.fragmentContainer, fragment2, "2")
.addToBackStack(null)
.commit();
- mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+ mActivityRule.runOnUiThread(fm1::executePendingTransactions);
FragmentTestUtil.waitForExecution(mActivityRule);
fm1.popBackStack();
- mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+ mActivityRule.runOnUiThread(fm1::executePendingTransactions);
FragmentTestUtil.waitForExecution(mActivityRule);
// Now fragment2 should be animating away
assertFalse(fragment2.isAdded());
diff --git a/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
index 7d65b8c..6e6cda9 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
@@ -41,11 +41,8 @@
public ActivityTestRule<FragmentTestActivity> mActivityRule =
new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
- private Instrumentation mInstrumentation;
-
@Before
public void setupContentView() {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
}
@@ -58,7 +55,7 @@
final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
final StrictViewFragment fragment = new StrictViewFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
fm.beginTransaction()
diff --git a/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
index f91eb65..bbd8d10 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
@@ -15,11 +15,11 @@
*/
package android.fragment.cts;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.app.FragmentManager;
-import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -39,14 +39,12 @@
private ViewGroup mContainer;
private FragmentManager mFM;
- private Instrumentation mInstrumentation;
@Before
public void setup() {
FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
mContainer = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
mFM = mActivityRule.getActivity().getFragmentManager();
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
}
// Test that when you add and replace a fragment that only the replace's add
@@ -55,7 +53,7 @@
public void addReplace() throws Throwable {
final CountCallsFragment fragment1 = new CountCallsFragment();
final StrictViewFragment fragment2 = new StrictViewFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
@@ -69,7 +67,7 @@
assertEquals(0, fragment1.onCreateViewCount);
FragmentTestUtil.assertChildren(mContainer, fragment2);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.popBackStack();
@@ -92,7 +90,7 @@
FragmentTestUtil.assertChildren(mContainer, fragment1);
// Now pop and add
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.popBackStack();
@@ -116,7 +114,7 @@
public void middlePop() throws Throwable {
final CountCallsFragment fragment1 = new CountCallsFragment();
final CountCallsFragment fragment2 = new CountCallsFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
@@ -146,7 +144,7 @@
public void optimizeRemove() throws Throwable {
final CountCallsFragment fragment1 = new CountCallsFragment();
final int[] id = new int[1];
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
id[0] = mFM.beginTransaction()
@@ -186,7 +184,7 @@
FragmentTestUtil.executePendingTransactions(mActivityRule);
assertEquals(1, fragment1.onCreateViewCount);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
@@ -224,7 +222,7 @@
assertEquals(1, fragment1.onAttachCount);
FragmentTestUtil.assertChildren(mContainer, fragment1);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
@@ -274,7 +272,7 @@
assertEquals(0, fragment1.onCreateViewCount);
FragmentTestUtil.assertChildren(mContainer);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
@@ -318,7 +316,7 @@
assertEquals(1, fragment1.onHideCount);
FragmentTestUtil.assertChildren(mContainer, fragment1);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
@@ -353,7 +351,7 @@
assertEquals(0, fragment1.onShowCount);
assertEquals(1, fragment1.onHideCount);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
@@ -373,7 +371,7 @@
assertEquals(0, fragment1.onShowCount);
assertEquals(1, fragment1.onHideCount);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
@@ -408,7 +406,7 @@
assertEquals(0, fragment1.onHideCount);
FragmentTestUtil.assertChildren(mContainer, fragment1);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
@@ -445,7 +443,7 @@
final CountCallsFragment fragment2 = new CountCallsFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
@@ -470,7 +468,7 @@
@Test
public void addPopBackStack() throws Throwable {
final CountCallsFragment fragment1 = new CountCallsFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
@@ -493,7 +491,7 @@
public void popNonBackStack() throws Throwable {
final CountCallsFragment fragment1 = new CountCallsFragment();
final CountCallsFragment fragment2 = new CountCallsFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
@@ -519,7 +517,7 @@
public void noOptimization() throws Throwable {
final CountCallsFragment fragment1 = new CountCallsFragment();
final CountCallsFragment fragment2 = new CountCallsFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFM.beginTransaction()
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
index c175164..62c4906 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
@@ -23,10 +23,8 @@
import android.app.FragmentController;
import android.app.FragmentManager;
import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
import android.os.Looper;
import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.util.Pair;
import android.view.View;
@@ -42,9 +40,14 @@
// the UI thread and then the execution will be added onto the queue after that.
// The two-cycle wait makes sure fragments have the opportunity to complete both
// before returning.
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- instrumentation.runOnMainSync(() -> {});
- instrumentation.runOnMainSync(() -> {});
+ try {
+ rule.runOnUiThread(() -> {
+ });
+ rule.runOnUiThread(() -> {
+ });
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
}
private static void runOnUiThreadRethrow(ActivityTestRule<? extends Activity> rule,
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
index 43a9590..742137706 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
@@ -15,7 +15,8 @@
*/
package android.fragment.cts;
-import static junit.framework.Assert.*;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -23,22 +24,20 @@
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import com.android.compatibility.common.util.transition.TargetTracking;
-import com.android.compatibility.common.util.transition.TrackingTransition;
-
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
-import android.app.Instrumentation;
import android.app.SharedElementCallback;
import android.graphics.Rect;
import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.transition.TransitionSet;
import android.view.View;
+import com.android.compatibility.common.util.transition.TargetTracking;
+import com.android.compatibility.common.util.transition.TrackingTransition;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -68,7 +67,6 @@
public ActivityTestRule<FragmentTestActivity> mActivityRule =
new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
- private Instrumentation mInstrumentation;
private FragmentManager mFragmentManager;
public FragmentTransitionTest(final boolean optimize) {
@@ -77,7 +75,6 @@
@Before
public void setup() throws Throwable {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
mFragmentManager = mActivityRule.getActivity().getFragmentManager();
FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
}
@@ -163,7 +160,7 @@
final TransitionFragment fragment2 = new TransitionFragment();
fragment2.setLayoutId(R.layout.scene2);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mFragmentManager.beginTransaction()
@@ -966,7 +963,7 @@
final View startRed = findRed();
final Rect startSharedRect = getBoundsOnScreen(startBlue);
- mInstrumentation.runOnMainSync(() -> {
+ mActivityRule.runOnUiThread(() -> {
for (int i = 0; i < numPops; i++) {
mFragmentManager.popBackStack();
}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
index 6f96811..e9c80e0 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -46,13 +46,6 @@
public ActivityTestRule<FragmentTestActivity> mActivityRule =
new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
- private Instrumentation mInstrumentation;
-
- @Before
- public void setupInstrumentation() {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
- }
-
// Test that adding a fragment adds the Views in the proper order. Popping the back stack
// should remove the correct Views.
@Test
@@ -156,7 +149,7 @@
fm.beginTransaction().add(R.id.fragmentContainer, fragment1).commit();
FragmentTestUtil.executePendingTransactions(mActivityRule);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
@@ -917,7 +910,7 @@
final StrictViewFragment fragment2 = new StrictViewFragment();
final StrictViewFragment fragment3 = new StrictViewFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
fm.popBackStack();
diff --git a/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
index a3c43aa..2b89bc2 100644
--- a/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
+++ b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
@@ -26,10 +26,8 @@
import android.app.FragmentController;
import android.app.FragmentManager;
import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
import android.os.Bundle;
import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -50,12 +48,10 @@
public ActivityTestRule<FragmentTestActivity> mActivityRule =
new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
- private Instrumentation mInstrumentation;
private PostponedFragment1 mBeginningFragment;
@Before
public void setupContainer() throws Throwable {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
mBeginningFragment = new PostponedFragment1();
@@ -119,7 +115,7 @@
final int commit[] = new int[1];
// Need to run this on the UI thread so that the transaction doesn't start
// between the two
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
commit[0] = fm.beginTransaction()
@@ -489,7 +485,7 @@
final TransitionFragment fragment4 = new PostponedFragment2();
final StrictFragment strictFragment2 = new StrictFragment();
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
fm.beginTransaction()
@@ -539,7 +535,7 @@
final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
- mInstrumentation.runOnMainSync(new Runnable() {
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
fm.beginTransaction()
@@ -664,7 +660,7 @@
assertTrue(fragment2.isAdded());
assertTrue(fragment2.getView().isAttachedToWindow());
- mInstrumentation.runOnMainSync(() -> {
+ mActivityRule.runOnUiThread(() -> {
assertTrue(fm2.popBackStackImmediate());
});
diff --git a/hostsidetests/webkit/renderprocesscrash/Android.mk b/tests/pdf/Android.mk
similarity index 70%
rename from hostsidetests/webkit/renderprocesscrash/Android.mk
rename to tests/pdf/Android.mk
index 846cdc8..1e4a1ca 100644
--- a/hostsidetests/webkit/renderprocesscrash/Android.mk
+++ b/tests/pdf/Android.mk
@@ -1,4 +1,3 @@
-#
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,25 +11,34 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-# Don't include this package in any target.
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES :=
+
+LOCAL_MULTILIB := both
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES += \
+ android-support-test \
+ mockito-target-minus-junit4 \
+ compatibility-device-util \
+ ctstestrunner \
+ android-support-annotations \
+ junit \
+ legacy-android-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := CtsWebViewRendererCrash
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+LOCAL_PACKAGE_NAME := CtsPdfTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/tests/pdf/AndroidManifest.xml b/tests/pdf/AndroidManifest.xml
new file mode 100644
index 0000000..495b5da
--- /dev/null
+++ b/tests/pdf/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.graphics.pdf.cts">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.graphics.pdf.cts"
+ android:label="CTS tests of android.graphics.pdf">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/pdf/AndroidTest.xml b/tests/pdf/AndroidTest.xml
new file mode 100644
index 0000000..e7c0794
--- /dev/null
+++ b/tests/pdf/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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 Pdf test cases">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPdfTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.graphics.pdf.cts" />
+ <option name="runtime-hint" value="5m" />
+ </test>
+</configuration>
diff --git a/tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf b/tests/pdf/res/raw/a4_portrait_rgbb.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf
rename to tests/pdf/res/raw/a4_portrait_rgbb.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf b/tests/pdf/res/raw/a5_portrait_rgbb.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf
rename to tests/pdf/res/raw/a5_portrait_rgbb.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf b/tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
rename to tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf b/tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
rename to tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
Binary files differ
diff --git a/tests/pdf/res/raw/testimage.jpg b/tests/pdf/res/raw/testimage.jpg
new file mode 100644
index 0000000..d3dae03
--- /dev/null
+++ b/tests/pdf/res/raw/testimage.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/raw/two_pages.pdf b/tests/pdf/res/raw/two_pages.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/two_pages.pdf
rename to tests/pdf/res/raw/two_pages.pdf
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfDocumentTest.java
similarity index 100%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java
rename to tests/pdf/src/android/graphics/pdf/cts/PdfDocumentTest.java
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
similarity index 99%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
rename to tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
index 530ac1b..2f0158e 100644
--- a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
+++ b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
@@ -34,7 +34,7 @@
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
-import android.graphics.cts.R;
+import android.graphics.pdf.cts.R;
import android.graphics.pdf.PdfRenderer;
import android.graphics.pdf.PdfRenderer.Page;
import android.os.ParcelFileDescriptor;
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
similarity index 100%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
rename to tests/pdf/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java b/tests/pdf/src/android/graphics/pdf/cts/Utils.java
similarity index 98%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java
rename to tests/pdf/src/android/graphics/pdf/cts/Utils.java
index 2e2de3e..4d43e09 100644
--- a/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java
+++ b/tests/pdf/src/android/graphics/pdf/cts/Utils.java
@@ -53,8 +53,8 @@
static final int A4_WIDTH_PTS = 595;
static final int A4_HEIGHT_PTS = 841;
- static final int A4_PORTRAIT = android.graphics.cts.R.raw.a4_portrait_rgbb;
- static final int A5_PORTRAIT = android.graphics.cts.R.raw.a5_portrait_rgbb;
+ static final int A4_PORTRAIT = android.graphics.pdf.cts.R.raw.a4_portrait_rgbb;
+ static final int A5_PORTRAIT = android.graphics.pdf.cts.R.raw.a5_portrait_rgbb;
/**
* Create a {@link PdfRenderer} pointing to a file copied from a resource.
diff --git a/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java b/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
index 547f44c..8866a39 100644
--- a/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
@@ -40,7 +40,6 @@
*
* This testcase tests operation of:
* - SensorManager.createDirectChannel()
- * - SensorManager.configureDirectReport()
* - SensorDirectChannel.*
* - Sensor.getHighestDirectReportRateLevel()
* - Sensor.isDirectChannelTypeSupported()
@@ -89,7 +88,7 @@
protected void setUp() throws Exception {
mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
- mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_ASHMEM);
+ mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_MEMORY_FILE);
mNeedHardwareBuffer = isMemoryTypeNeeded(SensorDirectChannel.TYPE_HARDWARE_BUFFER);
if (mNeedMemoryFile) {
@@ -129,28 +128,28 @@
public void testAccelerometerAshmemNormal() {
runSensorDirectReportTest(
Sensor.TYPE_ACCELEROMETER,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_NORMAL);
}
public void testGyroscopeAshmemNormal() {
runSensorDirectReportTest(
Sensor.TYPE_GYROSCOPE,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_NORMAL);
}
public void testMagneticFieldAshmemNormal() {
runSensorDirectReportTest(
Sensor.TYPE_MAGNETIC_FIELD,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_NORMAL);
}
public void testAccelerometerAshmemFast() {
runSensorDirectReportTest(
Sensor.TYPE_ACCELEROMETER,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_FAST);
}
@@ -158,21 +157,21 @@
public void testGyroscopeAshmemFast() {
runSensorDirectReportTest(
Sensor.TYPE_GYROSCOPE,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_FAST);
}
public void testMagneticFieldAshmemFast() {
runSensorDirectReportTest(
Sensor.TYPE_MAGNETIC_FIELD,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_FAST);
}
public void testAccelerometerAshmemVeryFast() {
runSensorDirectReportTest(
Sensor.TYPE_ACCELEROMETER,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_VERY_FAST);
}
@@ -180,14 +179,14 @@
public void testGyroscopeAshmemVeryFast() {
runSensorDirectReportTest(
Sensor.TYPE_GYROSCOPE,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_VERY_FAST);
}
public void testMagneticFieldAshmemVeryFast() {
runSensorDirectReportTest(
Sensor.TYPE_MAGNETIC_FIELD,
- SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.TYPE_MEMORY_FILE,
SensorDirectChannel.RATE_VERY_FAST);
}
@@ -263,39 +262,40 @@
return;
}
- mChannel = null;
try {
switch(memType) {
- case SensorDirectChannel.TYPE_ASHMEM:
+ case SensorDirectChannel.TYPE_MEMORY_FILE:
assertTrue("MemoryFile is null", mMemoryFile != null);
mChannel = mSensorManager.createDirectChannel(mMemoryFile);
- assertTrue("createDirectChannel(MemoryFile) failed", mChannel != null);
break;
case SensorDirectChannel.TYPE_HARDWARE_BUFFER:
assertTrue("HardwareBuffer is null", mHardwareBuffer != null);
mChannel = mSensorManager.createDirectChannel(mHardwareBuffer);
- assertTrue("createDirectChannel(HardwareBuffer) failed", mChannel != null);
break;
default:
Log.e(TAG, "Specified illegal memory type " + memType);
return;
}
+ } catch (IllegalStateException e) {
+ mChannel = null;
+ }
+ assertTrue("createDirectChannel failed", mChannel != null);
+
+ try {
assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType));
waitBeforeStartSensor();
- int token = mSensorManager.configureDirectChannel(mChannel, s, rateLevel);
+ int token = mChannel.configure(s, rateLevel);
assertTrue("configure direct mChannel failed", token > 0);
waitSensorCollection();
//stop sensor and analyze content
- mSensorManager.configureDirectChannel(mChannel, s, SensorDirectChannel.RATE_STOP);
+ mChannel.configure(s, SensorDirectChannel.RATE_STOP);
checkSharedMemoryContent(s, memType, rateLevel, token);
} finally {
- if (mChannel != null) {
- mChannel.close();
- mChannel = null;
- }
+ mChannel.close();
+ mChannel = null;
}
}
@@ -348,7 +348,7 @@
}
private boolean isSharedMemoryFormatted(int memType) {
- if (memType == SensorDirectChannel.TYPE_ASHMEM) {
+ if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
if (!readMemoryFileContent()) {
Log.e(TAG, "Read MemoryFile content fail");
return false;
@@ -369,7 +369,7 @@
}
private void checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token) {
- if (memType == SensorDirectChannel.TYPE_ASHMEM) {
+ if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
assertTrue("read MemoryFile content failed", readMemoryFileContent());
} else {
assertTrue("read HardwareBuffer content failed", readHardwareBufferContent());
diff --git a/tests/signature/Android.mk b/tests/signature/Android.mk
index 6a8dcf9..8502c59 100644
--- a/tests/signature/Android.mk
+++ b/tests/signature/Android.mk
@@ -27,7 +27,9 @@
LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner \
+ compatibility-device-util \
+ android-support-test
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/AndroidManifest.xml
index 52090ce..41a4233 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.signature.cts">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application>
@@ -27,4 +28,4 @@
android:targetPackage="android.signature.cts"
android:label="API Signature Test"/>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/signature/AndroidTest.xml b/tests/signature/AndroidTest.xml
index 038d0d0..6d23620 100644
--- a/tests/signature/AndroidTest.xml
+++ b/tests/signature/AndroidTest.xml
@@ -14,6 +14,11 @@
limitations under the License.
-->
<configuration description="Config for CTS Signature test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsSignatureTestCases" />
+ <option name="version" value="1.0" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/signature-test-packages" />
<option name='run-command'
diff --git a/tests/signature/DynamicConfig.xml b/tests/signature/DynamicConfig.xml
new file mode 100644
index 0000000..e078476
--- /dev/null
+++ b/tests/signature/DynamicConfig.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<!--
+ Bug: 33305737 android.intent.action.ACTION_CARRIER_SETUP
+ Bug: 36980009 android.intent.action.QUICKBOOT_POWERON
+ Bug: 36977779 android.intent.action.MASTER_CLEAR
+-->
+<dynamicConfig>
+ <entry key ="intent_whitelist">
+ <value>android.intent.action.ACTION_CARRIER_SETUP</value>
+ <value>android.intent.action.QUICKBOOT_POWERON</value>
+ </entry>
+</dynamicConfig>
diff --git a/tests/signature/src/android/signature/cts/IntentTest.java b/tests/signature/src/android/signature/cts/IntentTest.java
index c0d3e84..3d674ab 100644
--- a/tests/signature/src/android/signature/cts/IntentTest.java
+++ b/tests/signature/src/android/signature/cts/IntentTest.java
@@ -57,6 +57,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
@@ -90,19 +92,21 @@
new File("/data/local/tmp/signature-test-packages");
private static final String ANDROID_INTENT_PREFIX = "android.intent.action";
private static final String ACTION_LINE_PREFIX = " Action: ";
- private static final Set<String> INTENT_WHITELIST = getIntentWhitelist();
+ private static final String MODULE_NAME = "CtsSignatureTestCases";
private PackageManager mPackageManager;
+ private Set<String> intentWhitelist;
@Before
- public void setupPackageManager() {
+ public void setupPackageManager() throws Exception {
mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
+ intentWhitelist = getIntentWhitelist();
}
@Test
public void shouldNotFindUnexpectedIntents() throws Exception {
Set<String> platformIntents = lookupPlatformIntents();
- platformIntents.addAll(INTENT_WHITELIST);
+ platformIntents.addAll(intentWhitelist);
Set<String> allInvalidIntents = new HashSet<>();
@@ -268,9 +272,18 @@
}
}
- private static Set<String> getIntentWhitelist() {
+ private static Set<String> getIntentWhitelist() throws Exception {
Set<String> whitelist = new HashSet<>();
+ DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(MODULE_NAME);
+ List<String> intentWhitelist = dcds.getValues("intent_whitelist");
+
+ // Log the whitelist Intent
+ for (String intent : intentWhitelist) {
+ Log.d(TAG, String.format("whitelist add: %s", intent));
+ whitelist.add(intent);
+ }
+
return whitelist;
}
}
diff --git a/tests/tests/bluetooth/Android.mk b/tests/tests/bluetooth/Android.mk
index d980e37..c02b23d 100644
--- a/tests/tests/bluetooth/Android.mk
+++ b/tests/tests/bluetooth/Android.mk
@@ -25,6 +25,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_JAVA_LIBRARIES += android.test.runner
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index fd1c7d2..066de74 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.os.ParcelUuid;
import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
@@ -85,6 +86,9 @@
if (!mLocationOn) {
TestUtils.enableLocation(getContext());
}
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ "pm grant android.bluetooth.cts android.permission.ACCESS_COARSE_LOCATION"
+ );
}
@Override
diff --git a/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java b/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
index c52aba6..a0d7f16 100644
--- a/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
+++ b/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
@@ -179,8 +179,11 @@
wipeContactsProvider();
+ // Accessing CP2 to make sure the process starts.
+ getDatabaseCreationTimestamp();
+
assertTrue("Didn't receive content change notification",
- latch.await(60, TimeUnit.SECONDS));
+ latch.await(120, TimeUnit.SECONDS));
assertEquals(ProviderStatus.CONTENT_URI, notifiedUri.get());
}
@@ -201,7 +204,10 @@
wipeContactsProvider();
+ // Accessing CP2 to make sure the process starts.
+ getDatabaseCreationTimestamp();
+
assertTrue("Didn't receive contacts wipe broadcast",
- latch.await(60, TimeUnit.SECONDS));
+ latch.await(120, TimeUnit.SECONDS));
}
}
diff --git a/tests/tests/content/AndroidManifest.xml b/tests/tests/content/AndroidManifest.xml
index 6d8126c..f9a5915 100644
--- a/tests/tests/content/AndroidManifest.xml
+++ b/tests/tests/content/AndroidManifest.xml
@@ -94,6 +94,11 @@
android:requiredFeature="android.software.cts"
android:requiredNotFeature="android.software.cts.undefined" />
+ <permission android:name="android.content.cts.SIGNATURE_PERMISSION"
+ android:protectionLevel="signature" />
+
+ <uses-permission android:name="android.content.cts.SIGNATURE_PERMISSION" />
+
<!-- Used for PackageManager test, don't delete! -->
<uses-configuration/>
<uses-feature android:name="android.hardware.camera" />
@@ -154,7 +159,8 @@
<action android:name="android.content.cts.BroadcastReceiverTest.BROADCAST_TESTABORT" />
</intent-filter>
</receiver>
- <receiver android:name="android.content.cts.MockReceiver">
+ <receiver android:name="android.content.cts.MockReceiver"
+ android:permission="android.content.cts.SIGNATURE_PERMISSION">
<intent-filter android:priority="1">
<action android:name="android.content.cts.BroadcastReceiverTest.BROADCAST_MOCKTEST" />
<action android:name="android.content.cts.BroadcastReceiverTest.BROADCAST_TESTABORT" />
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 096eef9..e34aa6e 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -331,14 +331,20 @@
}
public void testVoiceCommand() {
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- assertCanBeHandled(intent);
- assertDefaultHandlerValidPriority(intent);
+ PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+ Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+ assertCanBeHandled(intent);
+ assertDefaultHandlerValidPriority(intent);
+ }
}
public void testVoiceSearchHandsFree() {
- Intent intent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
- assertCanBeHandled(intent);
- assertDefaultHandlerValidPriority(intent);
+ PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+ Intent intent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+ assertCanBeHandled(intent);
+ assertDefaultHandlerValidPriority(intent);
+ }
}
}
diff --git a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
index 8f9aba69..d62d322 100644
--- a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
+++ b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
@@ -51,6 +51,8 @@
"android.content.cts.BroadcastReceiverTest.BROADCAST_DISABLED";
private static final String TEST_PACKAGE_NAME = "android.content.cts";
+ private static final String SIGNATURE_PERMISSION = "android.content.cts.SIGNATURE_PERMISSION";
+
private static final long SEND_BROADCAST_TIMEOUT = 15000;
private static final long START_SERVICE_TIMEOUT = 3000;
@@ -183,8 +185,8 @@
activity.unregisterReceiver(internalReceiver);
}
- public void testOnReceiverOrdered() throws InterruptedException {
- MockReceiverInternalOrder internalOrderReceiver = new MockReceiverInternalOrder();
+ public void testManifestReceiverPackage() throws InterruptedException {
+ MockReceiverInternal internalReceiver = new MockReceiverInternal();
Bundle map = new Bundle();
map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
@@ -194,14 +196,15 @@
getInstrumentation().getContext().sendOrderedBroadcast(
new Intent(ACTION_BROADCAST_MOCKTEST)
.setPackage(TEST_PACKAGE_NAME).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
- null, internalOrderReceiver,
+ null, internalReceiver,
null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
- internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+ internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
- assertEquals(RESULT_INTERNAL_FINAL_CODE, internalOrderReceiver.getResultCode());
- assertEquals(RESULT_INTERNAL_FINAL_DATA, internalOrderReceiver.getResultData());
+ // These are set by MockReceiver.
+ assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
+ assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
- Bundle resultExtras = internalOrderReceiver.getResultExtras(false);
+ Bundle resultExtras = internalReceiver.getResultExtras(false);
assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
@@ -209,6 +212,87 @@
assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
}
+ public void testManifestReceiverComponent() throws InterruptedException {
+ MockReceiverInternal internalReceiver = new MockReceiverInternal();
+
+ Bundle map = new Bundle();
+ map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
+ MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
+ map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
+ MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
+ getInstrumentation().getContext().sendOrderedBroadcast(
+ new Intent(ACTION_BROADCAST_MOCKTEST)
+ .setClass(getActivity(), MockReceiver.class)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+ null, internalReceiver,
+ null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
+ internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+
+ // These are set by MockReceiver.
+ assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
+ assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
+
+ Bundle resultExtras = internalReceiver.getResultExtras(false);
+ assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
+ resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
+ assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
+ resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
+ assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
+ }
+
+ public void testManifestReceiverPermission() throws InterruptedException {
+ MockReceiverInternal internalReceiver = new MockReceiverInternal();
+
+ Bundle map = new Bundle();
+ map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
+ MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
+ map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
+ MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
+ getInstrumentation().getContext().sendOrderedBroadcast(
+ new Intent(ACTION_BROADCAST_MOCKTEST)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+ SIGNATURE_PERMISSION, internalReceiver,
+ null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
+ internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+
+ // These are set by MockReceiver.
+ assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
+ assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
+
+ Bundle resultExtras = internalReceiver.getResultExtras(false);
+ assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
+ resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
+ assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
+ resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
+ assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
+ }
+
+ public void testNoManifestReceiver() throws InterruptedException {
+ MockReceiverInternal internalReceiver = new MockReceiverInternal();
+
+ Bundle map = new Bundle();
+ map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
+ MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
+ map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
+ MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
+ getInstrumentation().getContext().sendOrderedBroadcast(
+ new Intent(ACTION_BROADCAST_MOCKTEST).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+ null, internalReceiver,
+ null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
+ internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+
+ // The MockReceiver should not have run, so we should still have the initial result.
+ assertEquals(RESULT_INITIAL_CODE, internalReceiver.getResultCode());
+ assertEquals(RESULT_INITIAL_DATA, internalReceiver.getResultData());
+
+ Bundle resultExtras = internalReceiver.getResultExtras(false);
+ assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
+ resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
+ assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
+ assertEquals(MockReceiver.RESULT_EXTRAS_REMOVE_VALUE,
+ resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
+ }
+
public void testAbortBroadcast() throws InterruptedException {
MockReceiverInternalOrder internalOrderReceiver = new MockReceiverInternalOrder();
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index 0ceda3a..e5e8fe4 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -24,7 +24,6 @@
import android.content.res.AssetFileDescriptor;
import android.database.ContentObserver;
import android.database.Cursor;
-import android.database.PageViewCursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -35,6 +34,7 @@
import android.util.Log;
import com.android.compatibility.common.util.PollingCheck;
+import com.android.internal.util.ArrayUtils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -419,41 +419,10 @@
}
/**
- * Verifies that paging arguments are handled correctly
- * when the provider supports paging.
+ * Verifies that paging information is correctly relayed, and that
+ * honored arguments from a supporting client are returned correctly.
*/
- public void testQuery_InProcessProvider_NoAutoPaging() {
-
- mContentResolver.delete(TABLE1_URI, null, null);
- ContentValues values = new ContentValues();
-
- for (int i = 0; i < 100; i++) {
- values.put(COLUMN_KEY_NAME, i);
- mContentResolver.insert(TABLE1_URI, values);
- }
-
- Bundle queryArgs = new Bundle();
- queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
- queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
-
- mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
- int col = mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME);
-
- Bundle extras = mCursor.getExtras();
- extras = extras != null ? extras : Bundle.EMPTY;
-
- assertEquals(100, mCursor.getCount());
- assertFalse(extras.containsKey(PageViewCursor.EXTRA_AUTO_PAGED));
- assertFalse(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-
- mCursor.close();
- }
-
- /**
- * Verifies that paging arguments are handled correctly
- * when the provider supports paging.
- */
- public void testQuery_OutOfProcessProvider_AutoPaging() {
+ public void testQuery_PagedResults() {
Bundle queryArgs = new Bundle();
queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
@@ -461,88 +430,30 @@
queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 100);
mCursor = mContentResolver.query(
- TestPagingContentProvider.UNPAGED_DATA_URI, null, queryArgs, null);
-
- Bundle extras = mCursor.getExtras();
- extras = extras != null ? extras : Bundle.EMPTY;
-
- assertEquals(3, mCursor.getCount());
- assertTrue(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
- assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
- assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
-
- int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
-
- mCursor.moveToNext();
- assertEquals(10, mCursor.getInt(col));
- mCursor.moveToNext();
- assertEquals(11, mCursor.getInt(col));
- mCursor.moveToNext();
- assertEquals(12, mCursor.getInt(col));
-
- assertFalse(mCursor.moveToNext());
-
- mCursor.close();
- }
-
- /**
- * Verifies that paging arguments are handled correctly
- * when the provider supports paging.
- */
- public void testQuery_OutOfProcessProvider_AutoPaging_OffsetOutOfBounds() {
-
- Bundle queryArgs = new Bundle();
- queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
- queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
- queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 100);
-
- mCursor = mContentResolver.query(
- TestPagingContentProvider.UNPAGED_DATA_URI, null, queryArgs, null);
-
- Bundle extras = mCursor.getExtras();
- extras = extras != null ? extras : Bundle.EMPTY;
-
- assertEquals(3, mCursor.getCount());
- assertTrue(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
- assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
- assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
-
- int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
-
- mCursor.moveToNext();
- assertEquals(10, mCursor.getInt(col));
- mCursor.moveToNext();
- assertEquals(11, mCursor.getInt(col));
- mCursor.moveToNext();
- assertEquals(12, mCursor.getInt(col));
-
- assertFalse(mCursor.moveToNext());
-
- mCursor.close();
- }
-
- /**
- * Verifies that auto-paging isn't applied when the underlying remote
- * provider has already applied paging.
- */
- public void testQuery_OutOfProcessProvider_NoAutoPagingForAlreadyPagedResults() {
-
- Bundle queryArgs = new Bundle();
- queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 20);
- queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 2);
- queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 500);
-
- mCursor = mContentResolver.query(
TestPagingContentProvider.PAGED_DATA_URI, null, queryArgs, null);
Bundle extras = mCursor.getExtras();
extras = extras != null ? extras : Bundle.EMPTY;
- assertFalse(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
+ assertEquals(3, mCursor.getCount());
+ assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
+ assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
- // we don't test the contents of the self-paged cursor
- // because that's provided by TestPagingContentProvider
- // a test-only test support class.
+ String[] honoredArgs = extras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+ assertNotNull(honoredArgs);
+ assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
+ assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
+
+ int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
+
+ mCursor.moveToNext();
+ assertEquals(10, mCursor.getInt(col));
+ mCursor.moveToNext();
+ assertEquals(11, mCursor.getInt(col));
+ mCursor.moveToNext();
+ assertEquals(12, mCursor.getInt(col));
+
+ assertFalse(mCursor.moveToNext());
mCursor.close();
}
diff --git a/tests/tests/dpi/AndroidManifest.xml b/tests/tests/dpi/AndroidManifest.xml
index 118050e..8b02670 100644
--- a/tests/tests/dpi/AndroidManifest.xml
+++ b/tests/tests/dpi/AndroidManifest.xml
@@ -18,6 +18,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.dpi.cts">
+ <uses-sdk
+ android:minSdkVersion="23"
+ android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
index 45418cf..3015b07 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
@@ -49,6 +49,11 @@
// Check that all four orientations report the same configuration value.
for (int i = 0; i < ORIENTATIONS.length; i++) {
Activity activity = startOrientationActivity(ORIENTATIONS[i]);
+ if (activity.isInMultiWindowMode()) {
+ // activity.setRequestedOrientation has no effect in multiwindow mode.
+ tearDown();
+ return;
+ }
Configuration mConfig = activity.getResources().getConfiguration();
int actualSize = mConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
int actualLong = mConfig.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK;
diff --git a/tests/tests/graphics/assets/red-adobergb.png b/tests/tests/graphics/assets/red-adobergb.png
new file mode 100644
index 0000000..adbff91
--- /dev/null
+++ b/tests/tests/graphics/assets/red-adobergb.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/alpha_mask.png b/tests/tests/graphics/res/drawable-nodpi/alpha_mask.png
new file mode 100644
index 0000000..1d6177f
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/alpha_mask.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
index a137784..5454e2f 100644
--- 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
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 d5288d1..ea6441a 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_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index 237c86e..06eccb8 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
index 0a4b40f..64a6476 100644
--- 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
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
index 194f36c..a296659 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
@@ -26,6 +26,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,14 +38,18 @@
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BitmapColorSpaceTest {
+ private static final String LOG_TAG = "BitmapColorSpaceTest";
+
private Resources mResources;
@Before
@@ -52,12 +57,98 @@
mResources = InstrumentationRegistry.getTargetContext().getResources();
}
+ @SuppressWarnings("deprecation")
+ @Test
+ public void createWithColorSpace() {
+ Bitmap b;
+ ColorSpace cs;
+ ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
+
+ // We don't test HARDWARE configs because they are not compatible with mutable bitmaps
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, sRGB);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true,
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true, sRGB);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true,
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true, sRGB);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true,
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, sRGB);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true,
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true, sRGB);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true,
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(sRGB, cs);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void createWithoutColorSpace() {
+ Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void createWithNonRgbColorSpace() {
+ Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true,
+ ColorSpace.get(ColorSpace.Named.CIE_LAB));
+ }
+
@Test
public void sRGB() {
Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
}
@Test
@@ -67,6 +158,16 @@
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
+
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
+
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
@@ -79,6 +180,16 @@
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
} catch (IOException e) {
fail();
}
@@ -139,7 +250,7 @@
@Test
public void getPixel() {
- verifyGetPixel("green-p3.png", 0x75fb4cff, 0xff03ff00);
+ verifyGetPixel("green-p3.png", 0x75fb4cff, 0xff00ff00);
verifyGetPixel("translucent-green-p3.png", 0x3a7d267f, 0x7f00ff00); // 50% translucent
}
@@ -151,22 +262,34 @@
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
- ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
- b.copyPixelsToBuffer(dst);
- dst.rewind();
- // Stored as RGBA
- assertEquals(rawColor, dst.asIntBuffer().get());
+ verifyGetPixel(b, rawColor, srgbColor);
- int srgb = b.getPixel(31, 31);
- assertEquals(srgbColor, srgb);
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ verifyGetPixel(b, rawColor, srgbColor);
+
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ verifyGetPixel(b, rawColor, srgbColor);
} catch (IOException e) {
fail();
}
}
+ private static void verifyGetPixel(@NonNull Bitmap b,
+ @ColorInt int rawColor, @ColorInt int srgbColor) {
+ ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
+ b.copyPixelsToBuffer(dst);
+ dst.rewind();
+
+ // Stored as RGBA
+ assertEquals(rawColor, dst.asIntBuffer().get());
+
+ int srgb = b.getPixel(15, 15);
+ almostEqual(srgbColor, srgb, 3, 15 * b.getWidth() + 15);
+ }
+
@Test
public void getPixels() {
- verifyGetPixels("green-p3.png", 0xff03ff00);
+ verifyGetPixels("green-p3.png", 0xff00ff00);
verifyGetPixels("translucent-green-p3.png", 0x7f00ff00); // 50% translucent
}
@@ -177,16 +300,28 @@
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
- int[] pixels = new int[b.getWidth() * b.getHeight()];
- b.getPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
- for (int pixel : pixels) {
- assertEquals(expected, pixel);
- }
+ verifyGetPixels(b, expected);
+
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ verifyGetPixels(b, expected);
+
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ verifyGetPixels(b, expected);
} catch (IOException e) {
fail();
}
}
+ private static void verifyGetPixels(@NonNull Bitmap b, @ColorInt int expected) {
+ int[] pixels = new int[b.getWidth() * b.getHeight()];
+ b.getPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
+
+ for (int i = 0; i < pixels.length; i++) {
+ int pixel = pixels[i];
+ almostEqual(expected, pixel, 3, i);
+ }
+ }
+
@Test
public void setPixel() {
verifySetPixel("green-p3.png", 0xffff0000, 0xea3323ff);
@@ -204,18 +339,29 @@
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
- b.setPixel(0, 0, newColor);
+ verifySetPixel(b, newColor, expectedColor);
- ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
- b.copyPixelsToBuffer(dst);
- dst.rewind();
- // Stored as RGBA
- assertEquals(expectedColor, dst.asIntBuffer().get());
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ verifySetPixel(b, newColor, expectedColor);
+
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ verifySetPixel(b, newColor, expectedColor);
} catch (IOException e) {
fail();
}
}
+ private static void verifySetPixel(@NonNull Bitmap b,
+ @ColorInt int newColor, @ColorInt int expectedColor) {
+ b.setPixel(0, 0, newColor);
+
+ ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
+ b.copyPixelsToBuffer(dst);
+ dst.rewind();
+ // Stored as RGBA
+ assertEquals(expectedColor, dst.asIntBuffer().get());
+ }
+
@Test
public void setPixels() {
verifySetPixels("green-p3.png", 0xffff0000, 0xea3323ff);
@@ -233,25 +379,36 @@
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
- int[] pixels = new int[b.getWidth() * b.getHeight()];
- Arrays.fill(pixels, newColor);
- b.setPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
+ verifySetPixels(b, newColor, expectedColor);
- ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
- b.copyPixelsToBuffer(dst);
- dst.rewind();
+ b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
+ verifySetPixels(b, newColor, expectedColor);
- IntBuffer buffer = dst.asIntBuffer();
- //noinspection ForLoopReplaceableByForEach
- for (int i = 0; i < pixels.length; i++) {
- // Stored as RGBA
- assertEquals(expectedColor, buffer.get());
- }
+ b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
+ verifySetPixels(b, newColor, expectedColor);
} catch (IOException e) {
fail();
}
}
+ private static void verifySetPixels(@NonNull Bitmap b,
+ @ColorInt int newColor, @ColorInt int expectedColor) {
+ int[] pixels = new int[b.getWidth() * b.getHeight()];
+ Arrays.fill(pixels, newColor);
+ b.setPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
+
+ ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
+ b.copyPixelsToBuffer(dst);
+ dst.rewind();
+
+ IntBuffer buffer = dst.asIntBuffer();
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < pixels.length; i++) {
+ // Stored as RGBA
+ assertEquals(expectedColor, buffer.get());
+ }
+ }
+
@Test
public void writeColorSpace() {
verifyColorSpaceMarshalling("green-srgb.png", ColorSpace.get(ColorSpace.Named.SRGB));
@@ -370,6 +527,22 @@
}
@Test
+ public void guessAdobeRGB() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inJustDecodeBounds = true;
+
+ try (InputStream in = mResources.getAssets().open("red-adobergb.png")) {
+ Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+ ColorSpace cs = opts.outColorSpace;
+ assertNull(b);
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
public void guessUnknown() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
@@ -400,4 +573,158 @@
fail();
}
}
+
+ @Test
+ public void inColorSpaceP3ToSRGB() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+
+ try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+ Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+ ColorSpace cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+ assertEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+
+ verifyGetPixel(b, 0x3ff00ff, 0xff00ff00);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void inColorSpaceSRGBToP3() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+
+ try (InputStream in = mResources.getAssets().open("green-srgb.png")) {
+ Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+ ColorSpace cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
+ assertEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+
+ verifyGetPixel(b, 0x75fb4cff, 0xff00ff00);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void inColorSpaceRGBA16F() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+
+ try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
+ Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+ ColorSpace cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+ assertNotEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void inColorSpace565() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+ opts.inPreferredConfig = Bitmap.Config.RGB_565;
+
+ try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+ Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+ ColorSpace cs = b.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+ assertNotEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void inColorSpaceNotRGB() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+
+ try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+ BitmapFactory.decodeStream(in, null, opts);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void inColorSpaceNoTransferParameters() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+
+ try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+ BitmapFactory.decodeStream(in, null, opts);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void copy() {
+ Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot);
+ Bitmap c = b.copy(Bitmap.Config.ARGB_8888, false);
+ ColorSpace cs = c.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+
+ c = b.copy(Bitmap.Config.ARGB_8888, true);
+ cs = c.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+
+ try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+ b = BitmapFactory.decodeStream(in);
+ c = b.copy(Bitmap.Config.ARGB_8888, false);
+ cs = c.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
+
+ c = b.copy(Bitmap.Config.ARGB_8888, true);
+ cs = c.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
+ } catch (IOException e) {
+ fail();
+ }
+
+ try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
+ b = BitmapFactory.decodeStream(in);
+ c = b.copy(Bitmap.Config.RGBA_F16, false);
+ cs = c.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+
+ c = b.copy(Bitmap.Config.RGBA_F16, true);
+ cs = c.getColorSpace();
+ assertNotNull(cs);
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private static void almostEqual(@ColorInt int expected,
+ @ColorInt int pixel, int threshold, int index) {
+ int diffA = Math.abs(expected >>> 24 - pixel >>> 24);
+ int diffR = Math.abs((expected >> 16) & 0xff - (pixel >> 16) & 0xff);
+ int diffG = Math.abs((expected >> 8) & 0xff - (pixel >> 8) & 0xff);
+ int diffB = Math.abs((expected ) & 0xff - (pixel ) & 0xff);
+
+ boolean pass = diffA + diffR + diffG + diffB < threshold;
+ if (!pass) {
+ Log.d(LOG_TAG, "Expected 0x" + Integer.toHexString(expected) +
+ " but was 0x" + Integer.toHexString(pixel) + " with index " + index);
+ }
+
+ assertTrue(pass);
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRGBAF16Test.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRGBAF16Test.java
index 114a385..02c9425 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRGBAF16Test.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRGBAF16Test.java
@@ -15,38 +15,41 @@
*/
package android.graphics.cts;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BitmapRGBAF16Test {
private Bitmap mOpaqueBitmap;
private Bitmap mTransparentBitmap;
+ private Resources mResources;
@Before
public void setup() {
- Resources resources = InstrumentationRegistry.getTargetContext().getResources();
+ mResources = InstrumentationRegistry.getTargetContext().getResources();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
// The bitmaps are in raw-nodpi/ to guarantee aapt and framework leave them untouched
- mOpaqueBitmap = BitmapFactory.decodeResource(resources, R.raw.p3_opaque, options);
- mTransparentBitmap = BitmapFactory.decodeResource(resources, R.raw.p3_transparent, options);
+ mOpaqueBitmap = BitmapFactory.decodeResource(mResources, R.raw.p3_opaque, options);
+ mTransparentBitmap = BitmapFactory.decodeResource(mResources, R.raw.p3_transparent, options);
}
@Test
@@ -133,4 +136,16 @@
assertTrue(before != after);
assertEquals(0x7f102030, after);
}
+
+ @Test
+ public void testCopyFromA8() {
+ Bitmap res = BitmapFactory.decodeResource(mResources, R.drawable.alpha_mask);
+ Bitmap mask = Bitmap.createBitmap(res.getWidth(), res.getHeight(),
+ Bitmap.Config.ALPHA_8);
+ Canvas c = new Canvas(mask);
+ c.drawBitmap(res, 0, 0, null);
+
+ Bitmap b = mask.copy(Config.RGBA_F16, false);
+ assertNotNull(b);
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index 04b4aba..aea201c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -31,9 +31,11 @@
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorSpace;
import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -63,9 +65,33 @@
R.drawable.gif_test, R.drawable.bmp_test
};
private static final String[] NAMES_TEMP_FILES = new String[] {
- "baseline_temp.jpg", "progressive_temp.jpg", "baseline_restart_temp.jpg",
- "progressive_restart_temp.jpg", "png_temp.png", "webp_temp.webp",
- "gif_temp.gif", "bmp_temp.bmp"
+ "baseline_temp.jpg", "progressive_temp.jpg", "baseline_restart_temp.jpg",
+ "progressive_restart_temp.jpg", "png_temp.png", "webp_temp.webp",
+ "gif_temp.gif", "bmp_temp.bmp"
+ };
+
+ // Do not change the order!
+ private static final String[] ASSET_NAMES = {
+ "prophoto-rgba16f.png",
+ "green-p3.png",
+ "red-adobergb.png",
+ "green-srgb.png",
+ };
+ private static final ColorSpace.Named[][] ASSET_COLOR_SPACES = {
+ // ARGB8888
+ {
+ ColorSpace.Named.LINEAR_EXTENDED_SRGB,
+ ColorSpace.Named.DISPLAY_P3,
+ ColorSpace.Named.ADOBE_RGB,
+ ColorSpace.Named.SRGB
+ },
+ // RGB565
+ {
+ ColorSpace.Named.SRGB,
+ ColorSpace.Named.SRGB,
+ ColorSpace.Named.SRGB,
+ ColorSpace.Named.SRGB
+ }
};
// The width and height of the above image.
@@ -78,6 +104,7 @@
private static final int NUM_TEST_IMAGES = 6;
private static final int TILE_SIZE = 256;
+ private static final int SMALL_TILE_SIZE = 16;
// Configurations for BitmapFactory.Options
private static final Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888,
@@ -171,6 +198,7 @@
}
}
+ @LargeTest
@Test
public void testDecodeRegionInputStream() throws IOException {
Options opts = new BitmapFactory.Options();
@@ -197,6 +225,7 @@
}
}
+ @LargeTest
@Test
public void testDecodeRegionInputStreamInBitmap() throws IOException {
Options opts = new BitmapFactory.Options();
@@ -228,6 +257,7 @@
}
}
+ @LargeTest
@Test
public void testDecodeRegionByteArray() throws IOException {
Options opts = new BitmapFactory.Options();
@@ -255,6 +285,7 @@
}
}
+ @LargeTest
@Test
public void testDecodeRegionStringAndFileDescriptor() throws IOException {
Options opts = new BitmapFactory.Options();
@@ -327,6 +358,7 @@
// (2) The width, height, and Config of inBitmap are never changed.
// (3) All of the pixels decoded into inBitmap exactly match the pixels
// of a decode where inBitmap is NULL.
+ @LargeTest
@Test
public void testInBitmapReuse() throws IOException {
Options defaultOpts = new BitmapFactory.Options();
@@ -409,6 +441,145 @@
assertEquals(Config.HARDWARE, hardwareBitmap.getConfig());
}
+ @Test
+ public void testOutColorType() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
+ for (int j = 0; j < SAMPLESIZES.length; ++j) {
+ for (int k = 0; k < COLOR_CONFIGS.length; ++k) {
+ opts.inSampleSize = SAMPLESIZES[j];
+ opts.inPreferredConfig = COLOR_CONFIGS[k];
+
+ InputStream is1 = obtainInputStream(RES_IDS[i]);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(
+ new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+ decoder.recycle();
+
+ assertSame(opts.inPreferredConfig, opts.outConfig);
+ assertSame(opts.outConfig, region.getConfig());
+ region.recycle();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testOutColorSpace() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ for (int i = 0; i < ASSET_NAMES.length; i++) {
+ for (int j = 0; j < SAMPLESIZES.length; ++j) {
+ for (int k = 0; k < COLOR_CONFIGS.length; ++k) {
+ opts.inPreferredConfig = COLOR_CONFIGS[k];
+
+ String assetName = ASSET_NAMES[i];
+ InputStream is1 = obtainInputStream(assetName);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(
+ new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+ decoder.recycle();
+
+ ColorSpace expected = ColorSpace.get(ASSET_COLOR_SPACES[k][i]);
+ assertSame(expected, opts.outColorSpace);
+ assertSame(expected, region.getColorSpace());
+ region.recycle();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testReusedColorSpace() throws IOException {
+ Bitmap b = Bitmap.createBitmap(SMALL_TILE_SIZE, SMALL_TILE_SIZE, Config.ARGB_8888,
+ false, ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+
+ Options opts = new BitmapFactory.Options();
+ opts.inBitmap = b;
+
+ // sRGB
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+ obtainInputStream(ASSET_NAMES[3]), false);
+ Bitmap region = decoder.decodeRegion(
+ new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+ decoder.recycle();
+
+ assertEquals(ColorSpace.get(ColorSpace.Named.SRGB), region.getColorSpace());
+
+ // DisplayP3
+ decoder = BitmapRegionDecoder.newInstance(obtainInputStream(ASSET_NAMES[1]), false);
+ region = decoder.decodeRegion(new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+ decoder.recycle();
+
+ assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), region.getColorSpace());
+ }
+
+ @Test
+ public void testInColorSpace() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
+ for (int j = 0; j < SAMPLESIZES.length; ++j) {
+ opts.inSampleSize = SAMPLESIZES[j];
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+
+ InputStream is1 = obtainInputStream(RES_IDS[i]);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+ decoder.recycle();
+
+ assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), opts.outColorSpace);
+ assertSame(opts.outColorSpace, region.getColorSpace());
+ region.recycle();
+ }
+ }
+ }
+
+ @Test
+ public void testInColorSpaceRGBA16F() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+
+ InputStream is1 = obtainInputStream(ASSET_NAMES[0]); // ProPhoto 16 bit
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+ decoder.recycle();
+
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), region.getColorSpace());
+ region.recycle();
+ }
+
+ @Test
+ public void testInColorSpace565() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ opts.inPreferredConfig = Config.RGB_565;
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+
+ InputStream is1 = obtainInputStream(ASSET_NAMES[1]); // Display P3
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+ decoder.recycle();
+
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), region.getColorSpace());
+ region.recycle();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInColorSpaceNotRgb() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+ InputStream is1 = obtainInputStream(RES_IDS[0]);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInColorSpaceNoTransferParameters() throws IOException {
+ Options opts = new BitmapFactory.Options();
+ opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+ InputStream is1 = obtainInputStream(RES_IDS[0]);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+ Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+ }
+
private void compareRegionByRegion(BitmapRegionDecoder decoder,
Options opts, int mseMargin, Bitmap wholeImage) {
int width = decoder.getWidth();
@@ -459,6 +630,10 @@
return mRes.openRawResource(resId);
}
+ private InputStream obtainInputStream(String assetName) throws IOException {
+ return mRes.getAssets().open(assetName);
+ }
+
private byte[] obtainByteArray(int resId) throws IOException {
InputStream is = obtainInputStream(resId);
ByteArrayOutputStream os = new ByteArrayOutputStream();
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
index 1cc81bf..0b4f29f 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
@@ -161,35 +161,4 @@
Assert.assertArrayEquals(new int[] { Color.RED, Color.BLUE, Color.BLUE, Color.RED },
pixels);
}
-
- @Test
- public void testSetTileMode() {
- Bitmap bitmap = Bitmap.createBitmap(2, 1, Config.ARGB_8888);
- bitmap.setPixel(0, 0, Color.RED);
- bitmap.setPixel(1, 0, Color.BLUE);
- Bitmap dstBitmap = Bitmap.createBitmap(4, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(dstBitmap);
- Paint paint = new Paint();
- int[] pixels = new int[4];
-
-
- // use clamp, verify
- BitmapShader shader = new BitmapShader(bitmap,
- Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
- paint.setShader(shader);
- canvas.drawRect(0, 0, 4, 1, paint);
-
- dstBitmap.getPixels(pixels, 0, 4, 0, 0, 4, 1);
- Assert.assertArrayEquals(new int[] { Color.RED, Color.BLUE, Color.BLUE, Color.BLUE },
- pixels);
-
- // set to use mirror, verify
- // Note: we don't need to re-apply shader on paint, it's picked up automatically.
- shader.set(bitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
- canvas.drawRect(0, 0, 4, 1, paint);
-
- dstBitmap.getPixels(pixels, 0, 4, 0, 0, 4, 1);
- Assert.assertArrayEquals(new int[] { Color.RED, Color.BLUE, Color.BLUE, Color.RED },
- pixels);
- }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index 05f74f8..a113afa 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -166,6 +166,35 @@
}
@Test
+ public void testSetBitmapCleanClip() {
+ mCanvas.setBitmap(Bitmap.createBitmap(10, 10, Config.ARGB_8888));
+ Rect r = new Rect(2, 2, 8, 8);
+ mCanvas.save();
+ mCanvas.clipRect(r);
+ assertEquals(r, mCanvas.getClipBounds());
+
+ // "reset" the canvas, and then check that the clip is wide open
+ // and not the previous value
+
+ mCanvas.setBitmap(Bitmap.createBitmap(20, 20, Config.ARGB_8888));
+ r = new Rect(0, 0, 20, 20);
+ assertEquals(r, mCanvas.getClipBounds());
+ }
+
+ @Test
+ public void testSetBitmapSaveCount() {
+ Canvas c = new Canvas(Bitmap.createBitmap(10, 10, Config.ARGB_8888));
+ int initialSaveCount = c.getSaveCount();
+
+ c.save();
+ assertEquals(c.getSaveCount(), initialSaveCount + 1);
+
+ // setBitmap should restore the saveCount to its original/base value
+ c.setBitmap(Bitmap.createBitmap(10, 10, Config.ARGB_8888));
+ assertEquals(c.getSaveCount(), initialSaveCount);
+ }
+
+ @Test
public void testIsOpaque() {
assertFalse(mCanvas.isOpaque());
}
@@ -1083,6 +1112,19 @@
}
@Test
+ public void testClipInversePath() {
+ final Path p = new Path();
+ p.addRoundRect(new RectF(0, 0, 10, 10), 0.5f, 0.5f, Direction.CW);
+ p.setFillType(Path.FillType.INVERSE_WINDING);
+ assertTrue(mCanvas.clipPath(p, Op.INTERSECT));
+
+ mCanvas.drawColor(PAINT_COLOR);
+
+ assertEquals(Color.TRANSPARENT, mMutableBitmap.getPixel(0, 0));
+ assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 20));
+ }
+
+ @Test
public void testGetDrawFilter() {
assertNull(mCanvas.getDrawFilter());
final DrawFilter dF = new DrawFilter();
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
index f8714ee..61d46b2 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
@@ -15,7 +15,6 @@
*/
package android.graphics.cts;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.graphics.Bitmap;
@@ -98,55 +97,5 @@
canvas.drawPoint(0, 0, paint);
ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(0, 0));
}
-
- @Test
- public void testGetSetMatrix() {
- ColorMatrixColorFilter filter = new ColorMatrixColorFilter(new ColorMatrix());
- ColorMatrix getMatrix = new ColorMatrix();
- filter.getColorMatrix(getMatrix);
- assertEquals(new ColorMatrix(), getMatrix);
-
- ColorMatrix scaleTranslate = new ColorMatrix(new float[] {
- 2, 0, 0, 0, 5,
- 0, 2, 0, 0, 5,
- 0, 0, 2, 0, 5,
- 0, 0, 0, 2, 5
- });
-
- filter.setColorMatrix(scaleTranslate);
-
- filter.getColorMatrix(getMatrix);
- assertEquals(scaleTranslate, getMatrix);
- assertArrayEquals(scaleTranslate.getArray(), getMatrix.getArray(), 0);
-
- filter.setColorMatrixArray(null);
- filter.getColorMatrix(getMatrix);
- assertEquals(new ColorMatrix(), getMatrix);
- }
-
- @Test
- public void testSetMatrixDraw() {
- ColorMatrixColorFilter filter = new ColorMatrixColorFilter(new ColorMatrix(new float[] {
- 2, 0, 0, 0, 5,
- 0, 2, 0, 0, 5,
- 0, 0, 2, 0, 5,
- 0, 0, 0, 1, 0
- }));
-
- Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setColorFilter(filter);
-
-
- paint.setColor(0xFF101010);
- canvas.drawPaint(paint);
- ColorUtils.verifyColor(0xFF252525, bitmap.getPixel(0, 0));
-
-
- filter.setColorMatrix(null);
- canvas.drawPaint(paint);
- ColorUtils.verifyColor(0xFF101010, bitmap.getPixel(0, 0));
- }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java b/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java
index 2e76b85..f7893c7 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java
@@ -84,6 +84,11 @@
assertEquals(p3, colorSpace(pack(0.5f, 0.7f, 1.0f, 1.0f, p3)));
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidColorSpace() {
+ colorSpace(0xffffffffffffffffL);
+ }
+
@Test
public void testIsSrgb() {
ColorSpace p3 = ColorSpace.get(Named.DISPLAY_P3);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
index 2a83f32..8c8911e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
@@ -101,72 +101,6 @@
}
@Test
- public void testSet() {
- 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 redShader = new BitmapShader(redBitmap, TileMode.CLAMP, TileMode.CLAMP);
- BitmapShader cyanShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
-
- PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
-
- ComposeShader shader = new ComposeShader(redShader, cyanShader, xferMode);
-
- Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setShader(shader);
- canvas.drawPaint(paint);
-
- // red + cyan = white
- assertEquals(Color.WHITE, bitmap.getPixel(0, 0));
-
- // set to be multiply mode, and immediately redraw
- shader.set(redShader, cyanShader, PorterDuff.Mode.MULTIPLY);
- canvas.drawPaint(paint);
-
- // red * cyan = black
- assertEquals(Color.BLACK, bitmap.getPixel(0, 0));
- }
-
- @Test
- public void testInnerShaderMutate() {
- // verify that calling a setter on a child shader updates this shader
- 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);
- Bitmap greenBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- greenBitmap.eraseColor(Color.GREEN);
-
- BitmapShader redShader = new BitmapShader(redBitmap, TileMode.CLAMP, TileMode.CLAMP);
- BitmapShader cyanShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
-
- ComposeShader shader = new ComposeShader(redShader, cyanShader, PorterDuff.Mode.ADD);
-
-
- Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setShader(shader);
- canvas.drawPaint(paint);
-
- // red + cyan = white
- assertEquals(Color.WHITE, bitmap.getPixel(0, 0));
-
- // update one of the child shaders to point at a different bitmap
- cyanShader.set(greenBitmap, TileMode.CLAMP, TileMode.CLAMP);
-
- // and verify the change is picked up immediately by next paint
- canvas.drawPaint(paint);
-
- // red + green = yellow
- assertEquals(Color.YELLOW, bitmap.getPixel(0, 0));
- }
-
- @Test
public void testChildLocalMatrix() {
Matrix translate1x1 = new Matrix();
translate1x1.setTranslate(1, 1);
diff --git a/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java b/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java
index 929cd96..8aeefba 100644
--- a/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java
@@ -37,19 +37,18 @@
@Test
public void testConstruction() throws FontVariationAxis.InvalidFormatException {
- new FontVariationAxis("abcd", 1.0f);
- new FontVariationAxis(" ", 0.0f);
- new FontVariationAxis("A X ", -1.0f);
+ new FontVariationAxis("wght", 1.0f);
+ new FontVariationAxis("PRIV", -1.0f);
}
@Test
public void testGetterTest() throws FontVariationAxis.InvalidFormatException {
- FontVariationAxis axis = new FontVariationAxis("abcd", 1.0f);
- assertEquals("abcd", axis.getTag());
+ FontVariationAxis axis = new FontVariationAxis("wght", 1.0f);
+ assertEquals("wght", axis.getTag());
assertEquals(1.0f, axis.getStyleValue(), FLOT_EQUALITY_PREC);
- axis = new FontVariationAxis(" ", -1.0f);
- assertEquals(" ", axis.getTag());
+ axis = new FontVariationAxis("PRIV", -1.0f);
+ assertEquals("PRIV", axis.getTag());
assertEquals(-1.0f, axis.getStyleValue(), FLOT_EQUALITY_PREC);
}
@@ -94,36 +93,36 @@
assertEquals("wdth", axes[0].getTag());
assertEquals(0.5f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- axes = FontVariationAxis.fromFontVariationSettings("'AX ' 1");
+ axes = FontVariationAxis.fromFontVariationSettings("'PRIV' 1");
assertEquals(1, axes.length);
- assertEquals("AX ", axes[0].getTag());
+ assertEquals("PRIV", axes[0].getTag());
assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- axes = FontVariationAxis.fromFontVariationSettings("'AX '\t1");
+ axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\t1");
assertEquals(1, axes.length);
- assertEquals("AX ", axes[0].getTag());
+ assertEquals("PRIV", axes[0].getTag());
assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- axes = FontVariationAxis.fromFontVariationSettings("'AX '\n1");
+ axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\n1");
assertEquals(1, axes.length);
- assertEquals("AX ", axes[0].getTag());
+ assertEquals("PRIV", axes[0].getTag());
assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- axes = FontVariationAxis.fromFontVariationSettings("'AX '\r1");
+ axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\r1");
assertEquals(1, axes.length);
- assertEquals("AX ", axes[0].getTag());
+ assertEquals("PRIV", axes[0].getTag());
assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- axes = FontVariationAxis.fromFontVariationSettings("'AX '\r\t\n 1");
+ axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\r\t\n 1");
assertEquals(1, axes.length);
- assertEquals("AX ", axes[0].getTag());
+ assertEquals("PRIV", axes[0].getTag());
assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- axes = FontVariationAxis.fromFontVariationSettings("'wdth' 10,'AX '\r1");
+ axes = FontVariationAxis.fromFontVariationSettings("'wdth' 10,'PRIV'\r1");
assertEquals(2, axes.length);
assertEquals("wdth", axes[0].getTag());
assertEquals(10.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
- assertEquals("AX ", axes[1].getTag());
+ assertEquals("PRIV", axes[1].getTag());
assertEquals(1.0f, axes[1].getStyleValue(), FLOT_EQUALITY_PREC);
}
@@ -155,8 +154,7 @@
final FontVariationAxis[] axes = {
new FontVariationAxis("wght", 1.0f),
- new FontVariationAxis(" ", 2.0f),
- new FontVariationAxis("AX ", 3.0f)
+ new FontVariationAxis("PRIV", 3.0f)
};
String stringData = FontVariationAxis.toFontVariationSettings(axes);
diff --git a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
index e4ba072..da2b934 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
@@ -16,8 +16,6 @@
package android.graphics.cts;
-import static org.junit.Assert.assertEquals;
-
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
@@ -91,51 +89,4 @@
private void verifyColor(int expected, int actual) {
ColorUtils.verifyColor(expected, actual, TOLERANCE);
}
-
- @Test
- public void testGetSet() {
- LightingColorFilter filter = new LightingColorFilter(Color.WHITE, Color.BLACK);
- assertEquals(Color.WHITE, filter.getColorMultiply());
- assertEquals(Color.BLACK, filter.getColorAdd());
-
- filter.setColorMultiply(Color.RED);
- filter.setColorAdd(Color.BLUE);
-
- assertEquals(Color.RED, filter.getColorMultiply());
- assertEquals(Color.BLUE, filter.getColorAdd());
- }
-
- @Test
- public void testSetDraw() {
- LightingColorFilter filter = new LightingColorFilter(Color.CYAN, Color.BLACK);
-
- Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setColorFilter(filter);
-
- // test initial state
- paint.setColor(Color.YELLOW);
- canvas.drawPaint(paint);
- // Cyan * yellow = green
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0));
-
-
- // test set color multiply
- filter.setColorMultiply(Color.MAGENTA);
- paint.setColor(Color.YELLOW);
- canvas.drawPaint(paint);
- // Magenta * yellow = red
- ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0));
-
-
- // test set color add
- filter.setColorMultiply(Color.WHITE);
- filter.setColorAdd(Color.MAGENTA);
- paint.setColor(Color.GREEN);
- canvas.drawPaint(paint);
- // Magenta + green = white
- ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(0, 0));
-
- }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
index 8555193..185e6a1 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
@@ -84,35 +84,6 @@
}
@Test
- public void testSet() {
- // only using 2 pixel wide gradient since we don't care about interpolation here.
- // Note: we align start/end to be center pixel so colors at those pixels are exact.
- LinearGradient gradient = new LinearGradient(0.5f, 0, 1.5f, 0,
- Color.RED, Color.BLUE, TileMode.CLAMP);
-
- Bitmap bitmap = Bitmap.createBitmap(3, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
-
- Paint paint = new Paint();
- paint.setShader(gradient);
- canvas.drawPaint(paint);
-
-
- // red, blue, clamped to blue
- ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0), 5);
- ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(1, 0), 5);
- ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(2, 0), 5);
-
- gradient.set(0.5f, 0, 1.5f, 0, Color.GREEN, Color.WHITE, TileMode.MIRROR);
- canvas.drawPaint(paint);
-
- // green, white, mirrored to green
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0), 5);
- ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(1, 0), 5);
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(2, 0), 5);
- }
-
- @Test
public void testZeroScaleMatrix() {
LinearGradient gradient = new LinearGradient(0.5f, 0, 1.5f, 0,
Color.RED, Color.BLUE, TileMode.CLAMP);
diff --git a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
index f5c7aa3..22fa7c3 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
@@ -28,7 +28,7 @@
import android.graphics.Movie;
import android.graphics.Paint;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.WidgetTestUtils;
@@ -44,7 +44,7 @@
import java.io.InputStream;
import java.io.OutputStream;
-@MediumTest
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class MovieTest {
private final int MOVIE = R.drawable.animated;
diff --git a/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
index a2438ee..0beadae 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
@@ -27,8 +27,6 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.ColorUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,52 +81,4 @@
assertEquals(Color.CYAN, target.getPixel(width / 4, height * 3 / 4));
assertEquals(Color.CYAN, target.getPixel(width * 3 / 4, height * 3 / 4));
}
-
- @Test
- public void testGetSet() {
- PorterDuffColorFilter filter = new PorterDuffColorFilter(
- Color.RED, PorterDuff.Mode.MULTIPLY);
-
- assertEquals(Color.RED, filter.getColor());
- assertEquals(PorterDuff.Mode.MULTIPLY, filter.getMode());
-
- filter.setColor(Color.GREEN);
- filter.setMode(PorterDuff.Mode.ADD);
-
- assertEquals(Color.GREEN, filter.getColor());
- assertEquals(PorterDuff.Mode.ADD, filter.getMode());
- }
-
- @Test
- public void testSetDraw() {
- PorterDuffColorFilter filter = new PorterDuffColorFilter(
- Color.CYAN, PorterDuff.Mode.MULTIPLY);
-
- Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setColorFilter(filter);
-
- // test initial state
- paint.setColor(Color.YELLOW);
- canvas.drawPaint(paint);
- // Cyan * yellow = green
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0));
-
-
- // test set color
- filter.setColor(Color.MAGENTA);
- paint.setColor(Color.YELLOW);
- canvas.drawPaint(paint);
- // Magenta * yellow = red
- ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0));
-
-
- // test set mode
- filter.setMode(PorterDuff.Mode.ADD);
- paint.setColor(Color.GREEN);
- canvas.drawPaint(paint);
- // Magenta + green = white
- ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(0, 0));
- }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java
index e8a0cbc..d133bb9 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java
@@ -35,34 +35,6 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RadialGradientTest {
- @Test
- public void testSet() {
- // only using 1 pixel radius gradient since we don't care about interpolation here.
- // Note: we align start/end to be center pixel so colors at those pixels are exact.
- RadialGradient gradient = new RadialGradient(0.5f, 0.5f, 1,
- Color.RED, Color.BLUE, TileMode.CLAMP);
-
- Bitmap bitmap = Bitmap.createBitmap(3, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
-
- Paint paint = new Paint();
- paint.setShader(gradient);
- canvas.drawPaint(paint);
-
-
- // red, blue, clamped to blue
- ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0), 5);
- ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(1, 0), 5);
- ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(2, 0), 5);
-
- gradient.set(0.5f, 0.5f, 1, Color.GREEN, Color.WHITE, TileMode.MIRROR);
- canvas.drawPaint(paint);
-
- // green, white, mirrored to green
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0), 5);
- ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(1, 0), 5);
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(2, 0), 5);
- }
@Test
public void testZeroScaleMatrix() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
index ceea7a7..cb7ec0a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
@@ -22,7 +22,6 @@
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -148,33 +147,6 @@
}
@Test
- public void testSet() {
- // Only use two pixel wide bitmap since we don't care about interpolation here.
- // Note: we place the gradient in between the two pixels, so both are solid colors.
- SweepGradient gradient = new SweepGradient(1, 0.5f,
- new int[] {Color.BLUE, Color.RED, Color.BLUE}, null);
-
- Bitmap bitmap = Bitmap.createBitmap(2, 1, Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
-
- Paint paint = new Paint();
- paint.setShader(gradient);
- canvas.drawPaint(paint);
-
- // red to left, blue to right
- ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0), 5);
- ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(1, 0), 5);
-
- gradient.set(1, 0.5f,
- new int[] {Color.GREEN, Color.YELLOW, Color.GREEN}, null);
- canvas.drawPaint(paint);
-
- // yellow to left, green to right
- ColorUtils.verifyColor(Color.YELLOW, bitmap.getPixel(0, 0), 5);
- ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(1, 0), 5);
- }
-
- @Test
public void testZeroScaleMatrix() {
SweepGradient gradient = new SweepGradient(1, 0.5f,
new int[] {Color.BLUE, Color.RED, Color.BLUE}, null);
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index 36e3f12..3a1c1cf 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -21,11 +21,13 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
+import android.content.res.AssetManager;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.fonts.FontVariationAxis;
@@ -297,72 +299,53 @@
@Test
public void testTypefaceBuilder_AssetSource() throws FontVariationAxis.InvalidFormatException {
- Typeface.Builder builder = Typeface.Builder.obtain();
- try {
- Typeface typeface1 =
- builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf").build();
- assertNotNull(typeface1);
+ Typeface typeface1 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build();
+ assertNotNull(typeface1);
- builder.reset();
- Typeface typeface2 =
- builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf").build();
- assertNotNull(typeface2);
- assertSame("Same font asset should return same Typeface object", typeface1, typeface2);
+ Typeface typeface2 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build();
+ assertNotNull(typeface2);
+ assertSame("Same font asset should return same Typeface object", typeface1, typeface2);
- builder.reset();
- Typeface typeface3 =
- builder.setSourceFromAsset(mContext.getAssets(), "samplefont2.ttf").build();
- assertNotNull(typeface3);
- assertNotSame("Different font asset should return different Typeface object",
- typeface2, typeface3);
+ Typeface typeface3 = new Typeface.Builder(mContext.getAssets(), "samplefont2.ttf").build();
+ assertNotNull(typeface3);
+ assertNotSame("Different font asset should return different Typeface object",
+ typeface2, typeface3);
- builder.reset();
- Typeface typeface4 =
- builder.setSourceFromAsset(mContext.getAssets(), "samplefont3.ttf").build();
- assertNotNull(typeface4);
- assertNotSame("Different font asset should return different Typeface object",
- typeface2, typeface4);
- assertNotSame("Different font asset should return different Typeface object",
- typeface3, typeface4);
+ Typeface typeface4 = new Typeface.Builder(mContext.getAssets(), "samplefont3.ttf").build();
+ assertNotNull(typeface4);
+ assertNotSame("Different font asset should return different Typeface object",
+ typeface2, typeface4);
+ assertNotSame("Different font asset should return different Typeface object",
+ typeface3, typeface4);
- builder.reset();
- Typeface typeface5 =
- builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf")
- .setFontVariationSettings("'wdth' 1.0").build();
- assertNotNull(typeface5);
- assertNotSame("Different font font variation should return different Typeface object",
- typeface2, typeface5);
+ Typeface typeface5 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf")
+ .setFontVariationSettings("'wdth' 1.0").build();
+ assertNotNull(typeface5);
+ assertNotSame("Different font font variation should return different Typeface object",
+ typeface2, typeface5);
- builder.reset();
- Typeface typeface6 =
- builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf")
- .setFontVariationSettings("'wdth' 2.0").build();
- assertNotNull(typeface6);
- assertNotSame("Different font font variation should return different Typeface object",
- typeface2, typeface6);
- assertNotSame("Different font font variation should return different Typeface object",
- typeface5, typeface6);
+ Typeface typeface6 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf")
+ .setFontVariationSettings("'wdth' 2.0").build();
+ assertNotNull(typeface6);
+ assertNotSame("Different font font variation should return different Typeface object",
+ typeface2, typeface6);
+ assertNotSame("Different font font variation should return different Typeface object",
+ typeface5, typeface6);
- // TODO: Add ttc index case. Need TTC file for CTS. (b/36731640)
- } finally {
- builder.recycle();
- }
+ // TODO: Add ttc index case. Need TTC file for CTS. (b/36731640)
}
@Test
public void testTypefaceBuilder_FileSource() {
- Typeface.Builder builder = Typeface.Builder.obtain();
try {
File file = new File(obtainPath());
- Typeface typeface1 = builder.setSourceFromFile(file).build();
+ Typeface typeface1 = new Typeface.Builder(obtainPath()).build();
assertNotNull(typeface1);
- builder.reset();
- Typeface typeface2 = builder.setSourceFromFilePath(file.getAbsolutePath()).build();
+ Typeface typeface2 = new Typeface.Builder(file).build();
assertNotNull(typeface2);
- builder.reset();
- Typeface typeface3 = builder.setSourceFromFile(file)
+ Typeface typeface3 = new Typeface.Builder(file)
.setFontVariationSettings("'wdth' 1.0")
.build();
assertNotNull(typeface3);
@@ -372,20 +355,97 @@
// TODO: Add ttc index case. Need TTC file for CTS.
} catch (IOException | FontVariationAxis.InvalidFormatException e) {
throw new RuntimeException(e);
- } finally {
- builder.recycle();
}
}
@Test
+ public void testTypefaceBuilder_fallback() throws IOException {
+ final File validFile = new File(obtainPath());
+ final File invalidFile = new File("/some/invalid/path/to/font/file");
+ final AssetManager assets = mContext.getAssets();
+ // By default, returns null if no fallback font is specified.
+ assertNull(new Typeface.Builder(invalidFile).build());
+
+ assertNull(new Typeface.Builder(validFile)
+ .setTtcIndex(100 /* non-existing ttc index */).build());
+
+ assertNull(new Typeface.Builder(assets, "invalid path").build());
+
+ assertNull(new Typeface.Builder(assets, "samplefont.ttf")
+ .setTtcIndex(100 /* non-existing ttc index */).build());
+
+ // If fallback is set, the builder never returns null.
+ assertNotNull(new Typeface.Builder(invalidFile).setFallback("").build());
+
+ assertNotNull(new Typeface.Builder(invalidFile).setFallback("invalid name").build());
+
+ Typeface sansSerifTypeface = new Typeface.Builder(invalidFile)
+ .setFallback("sans-serif").build();
+ assertNotNull(sansSerifTypeface);
+
+ Typeface serifTypeface = new Typeface.Builder(invalidFile).setFallback("serif").build();
+ assertNotNull(serifTypeface);
+
+ Typeface boldSansSerifTypeface = new Typeface.Builder(invalidFile)
+ .setFallback("sans-serif").setWeight(700).build();
+ assertNotNull(boldSansSerifTypeface);
+
+ Typeface boldSerifTypeface = new Typeface.Builder(invalidFile)
+ .setFallback("serif").setWeight(700).build();
+ assertNotNull(boldSerifTypeface);
+
+ Typeface italicSansSerifTypeface = new Typeface.Builder(invalidFile)
+ .setFallback("sans-serif").setItalic(true).build();
+ assertNotNull(italicSansSerifTypeface);
+
+ Typeface italicSerifTypeface = new Typeface.Builder(invalidFile)
+ .setFallback("serif").setItalic(true).build();
+ assertNotNull(italicSerifTypeface);
+
+ // All fallbacks should be different each other.
+ assertNotSame(sansSerifTypeface, serifTypeface);
+ assertNotSame(sansSerifTypeface, boldSansSerifTypeface);
+ assertNotSame(sansSerifTypeface, boldSerifTypeface);
+ assertNotSame(sansSerifTypeface, italicSansSerifTypeface);
+ assertNotSame(sansSerifTypeface, italicSerifTypeface);
+ assertNotSame(serifTypeface, boldSansSerifTypeface);
+ assertNotSame(serifTypeface, boldSerifTypeface);
+ assertNotSame(serifTypeface, italicSansSerifTypeface);
+ assertNotSame(serifTypeface, italicSerifTypeface);
+ assertNotSame(boldSansSerifTypeface, boldSerifTypeface);
+ assertNotSame(boldSansSerifTypeface, italicSansSerifTypeface);
+ assertNotSame(boldSansSerifTypeface, italicSerifTypeface);
+ assertNotSame(boldSerifTypeface, italicSansSerifTypeface);
+ assertNotSame(boldSerifTypeface, italicSerifTypeface);
+ assertNotSame(italicSansSerifTypeface, italicSerifTypeface);
+
+ // Cache should work for the same fallback.
+ assertSame(sansSerifTypeface,
+ new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif")
+ .setTtcIndex(100 /* non-existing ttc index */).build());
+ assertSame(serifTypeface,
+ new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif")
+ .setTtcIndex(100 /* non-existing ttc index */).build());
+ assertSame(boldSansSerifTypeface,
+ new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif")
+ .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build());
+ assertSame(boldSerifTypeface,
+ new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif")
+ .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build());
+ assertSame(italicSansSerifTypeface,
+ new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif")
+ .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build());
+ assertSame(italicSerifTypeface,
+ new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif")
+ .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build());
+ }
+
+ @Test
public void testTypefaceBuilder_FileSourceFD() {
- Typeface.Builder builder = Typeface.Builder.obtain();
try (FileInputStream fis = new FileInputStream(obtainPath())) {
- assertNotNull(builder.setSourceFromFile(fis.getFD()).build());
+ assertNotNull(new Typeface.Builder(fis.getFD()).build());
} catch (IOException e) {
throw new RuntimeException(e);
- } finally {
- builder.recycle();
}
}
@@ -416,4 +476,27 @@
assertNotEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
}
}
+
+ @Test
+ public void testTypefaceBuilder_customFallback() {
+ final String fontPath = "samplefont2.ttf";
+ final Typeface regularTypeface = new Typeface.Builder(mContext.getAssets(), fontPath)
+ .setWeight(400).build();
+ final Typeface blackTypeface = new Typeface.Builder(mContext.getAssets(), fontPath)
+ .setWeight(900).build();
+
+ // W is not supported by samplefont2.ttf
+ final String testString = "WWWWWWWWWWWWWWWWWWWWW";
+
+ final Paint p = new Paint();
+ p.setTextSize(128);
+
+ p.setTypeface(regularTypeface);
+ final float widthFromRegular = p.measureText(testString);
+
+ p.setTypeface(blackTypeface);
+ final float widthFromBlack = p.measureText(testString);
+
+ assertTrue(Math.abs(widthFromRegular - widthFromBlack) > 1.0f);
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
index f8cd816..2e986cb 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
@@ -204,9 +204,11 @@
DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final StateListDrawable halfDrawable =
(StateListDrawable) cs.newDrawable(res);
+ // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+ final float approxHalf = (float)(densityDpi / 2) / densityDpi;
for (int i = 0; i < count; i++) {
halfDrawable.selectDrawable(i);
- assertEquals(Math.round(origWidth[i] / 2f), halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(origWidth[i] * approxHalf), halfDrawable.getIntrinsicWidth());
}
// Set density to double original.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
index 1c9f9b3..29da030 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
@@ -30,7 +30,9 @@
import android.graphics.cts.R;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
import android.view.View;
@@ -50,7 +52,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-@MediumTest
+@LargeTest
@RunWith(Parameterized.class)
public class AnimatedVectorDrawableParameterizedTest {
@Rule
@@ -183,6 +185,7 @@
return frameLatch.await(timeout, TimeUnit.MILLISECONDS);
}
+ @SmallTest
@Test
public void testSingleFrameAnimation() throws Throwable {
int resId = R.drawable.avd_single_frame;
@@ -208,6 +211,7 @@
});
}
+ @MediumTest
@Test
public void testEmptyAnimatorSet() throws Throwable {
int resId = R.drawable.avd_empty_animator;
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 65aad83..d1f6282 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -36,7 +36,8 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.AttributeSet;
@@ -50,7 +51,7 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-@MediumTest
+@LargeTest
@RunWith(AndroidJUnit4.class)
public class AnimatedVectorDrawableTest {
private static final int IMAGE_WIDTH = 64;
@@ -75,6 +76,7 @@
mResources = mActivity.getResources();
}
+ @SmallTest
@Test
public void testInflate() throws Exception {
// Setup AnimatedVectorDrawable from xml file
@@ -144,6 +146,7 @@
assertEquals(1, constantState.getChangingConfigurations());
}
+ @SmallTest
@Test
public void testMutate() {
AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
@@ -178,6 +181,7 @@
}
}
+ @SmallTest
@Test
public void testGetOpacity() {
AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
@@ -186,6 +190,7 @@
assertEquals("Still translucent", PixelFormat.TRANSLUCENT, d1.getOpacity());
}
+ @SmallTest
@Test
public void testColorFilter() {
PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
index 136ae2d..abba96e 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.DrawableContainer;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
@@ -39,7 +40,7 @@
* on animation duration scale. When the scale is 0, it is a static drawable, otherwise, it is an
* animatable drawable.
*/
-@MediumTest
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class CustomAnimationScaleListDrawableTest {
private static final int DRAWABLE_ID = R.drawable.custom_animation_scale_list_drawable;
@@ -58,7 +59,6 @@
ValueAnimator.setDurationScale(mOriginalScale);
}
- @MediumTest
@Test
public void testNonZeroDurationScale() {
// Set the duration scale to a non-zero value will cause the AnimationScaleListDrawable's
@@ -69,7 +69,6 @@
assertTrue(dr.getCurrent() instanceof Animatable);
}
- @MediumTest
@Test
public void testZeroDurationScale() {
// Set the duration scale to zero will cause the AnimationScaleListDrawable's current
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DefaultFocusHighlightTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DefaultFocusHighlightTest.java
new file mode 100644
index 0000000..c8d057a
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DefaultFocusHighlightTest.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2017 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.drawable.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.NinePatch;
+import android.graphics.Picture;
+import android.graphics.cts.R;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.graphics.drawable.DrawableContainer.DrawableContainerState;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LevelListDrawable;
+import android.graphics.drawable.NinePatchDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.graphics.drawable.PictureDrawable;
+import android.graphics.drawable.RippleDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.StateSet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DefaultFocusHighlightTest {
+
+ // The target context.
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ private static final int A_COLOR = 0x920424;
+ private static final int[] NO_STATE_FOCUSED = new int[] { android.R.attr.state_enabled };
+ private static final int[] ONLY_STATE_FOCUSED = new int[] { android.R.attr.state_focused };
+ private static final int[] STATE_FOCUSED_WITH_POS =
+ new int[] { android.R.attr.state_focused, android.R.attr.state_hovered };
+ private static final int[] STATE_FOCUSED_WITH_NEG =
+ new int[] { android.R.attr.state_focused, -android.R.attr.state_hovered };
+ private static final int[] STATE_FOCUSED_WITH_ENABLED =
+ new int[] { android.R.attr.state_focused, android.R.attr.state_enabled };
+
+ final static int[] FOCUSED_STATE =
+ new int[] { android.R.attr.state_focused, android.R.attr.state_enabled };
+
+ @UiThreadTest
+ @Test
+ public void testStateListDrawable() {
+ Drawable d;
+ // Empty state spec
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] {}
+ );
+ d.setState(FOCUSED_STATE);
+ assertFalse(d.hasFocusStateSpecified());
+
+ // Wild card
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] { StateSet.WILD_CARD }
+ );
+ d.setState(FOCUSED_STATE);
+ assertFalse(d.hasFocusStateSpecified());
+
+ // No state spec of state_focused=true
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] { NO_STATE_FOCUSED }
+ );
+ d.setState(FOCUSED_STATE);
+ assertFalse(d.hasFocusStateSpecified());
+
+ // One state spec of only state_focused=true
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] { ONLY_STATE_FOCUSED }
+ );
+ d.setState(FOCUSED_STATE);
+ assertTrue(d.hasFocusStateSpecified());
+
+ // One state spec of state_focused=true and something=true, but no state spec of
+ // state_focused=true and something=false (something is not enabled)
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] { STATE_FOCUSED_WITH_POS }
+ );
+ d.setState(FOCUSED_STATE);
+ assertTrue(d.hasFocusStateSpecified());
+
+ // One state spec of state_focused=true and something=true, and one spec of
+ // state_focused=true and something=false (something is not enabled)
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] { STATE_FOCUSED_WITH_POS, STATE_FOCUSED_WITH_NEG }
+ );
+ d.setState(FOCUSED_STATE);
+ assertTrue(d.hasFocusStateSpecified());
+
+ // One state spec of state_focused=true and enabled=true
+ d = DrawableFactory.createStateListDrawable(
+ new int[][] { STATE_FOCUSED_WITH_ENABLED }
+ );
+ d.setState(FOCUSED_STATE);
+ assertTrue(d.hasFocusStateSpecified());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testRippleDrawable() {
+ Drawable d = DrawableFactory.createRippleDrawable();
+ d.setState(FOCUSED_STATE);
+ assertTrue(d.hasFocusStateSpecified());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testPictureDrawable() {
+ Drawable d = DrawableFactory.createPictureDrawable(null);
+ d.setState(FOCUSED_STATE);
+ assertFalse(d.hasFocusStateSpecified());
+
+ d = DrawableFactory.createPictureDrawable(new Picture());
+ d.setState(FOCUSED_STATE);
+ assertFalse(d.hasFocusStateSpecified());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testColorStateListHandledDrawable() {
+ final Drawable[] drawables = new Drawable[] {
+ DrawableFactory.createShapeDrawable(),
+ DrawableFactory.createPaintDrawable(),
+ DrawableFactory.createBitmapDrawable(mContext),
+ DrawableFactory.createColorDrawable(),
+ DrawableFactory.createGradientDrawable(),
+ DrawableFactory.createNinePatchDrawable(mContext),
+ };
+ final ColorStateList[] stateLists = new ColorStateList[] {
+ // Empty state spec
+ new ColorStateList(
+ new int[][] { },
+ new int[] { }),
+ // Wild card
+ new ColorStateList(
+ new int[][] { StateSet.WILD_CARD },
+ new int[] { A_COLOR }),
+ // No state spec of state_focused=true
+ new ColorStateList(
+ new int[][] { NO_STATE_FOCUSED },
+ new int[] { A_COLOR }),
+ // One state spec of only state_focused=true
+ new ColorStateList(
+ new int[][] { ONLY_STATE_FOCUSED },
+ new int[] { A_COLOR }),
+ // One state spec of state_focused=true and something=true,
+ // but no state spec of state_focused=true and something=false
+ new ColorStateList(
+ new int[][] { STATE_FOCUSED_WITH_POS },
+ new int[] { A_COLOR }),
+ // One state spec of state_focused=true and something=true,
+ // and one spec of state_focused=true and something=false
+ new ColorStateList(
+ new int[][] { STATE_FOCUSED_WITH_POS, STATE_FOCUSED_WITH_NEG },
+ new int[] { A_COLOR, A_COLOR }),
+ };
+ final boolean[] expectedResults = new boolean[] {
+ // Empty state spec
+ false,
+ // Wild card
+ false,
+ // No state spec of state_focused=true
+ false,
+ // One state spec of only state_focused=true
+ true,
+ // One state spec of state_focused=true and something=true,
+ // but no state spec of state_focused=true and something=false
+ true,
+ // One state spec of state_focused=true and something=true,
+ // and one spec of state_focused=true and something=false
+ true
+ };
+ assertEquals(stateLists.length, expectedResults.length);
+ for (Drawable drawable : drawables) {
+ // No ColorStateList set
+ String drawableName = drawable.getClass().toString();
+ String errorMsg = "[" + drawableName + "] Testing no ColorStateList failed.";
+ drawable.setState(FOCUSED_STATE);
+ assertFalse(errorMsg, drawable.hasFocusStateSpecified());
+ // With ColorStateList set
+ for (int i = 0; i < stateLists.length; i++) {
+ ColorStateList stateList = stateLists[i];
+ boolean expectedResult = expectedResults[i];
+ drawable.setTintList(stateList);
+ errorMsg = "[" + drawableName + "] Testing ColorStateList No." + i + " failed.";
+
+ drawable.setState(FOCUSED_STATE);
+ if (expectedResult) {
+ assertTrue(errorMsg, drawable.hasFocusStateSpecified());
+ } else {
+ assertFalse(errorMsg, drawable.hasFocusStateSpecified());
+ }
+ }
+ }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testDrawableContainer() {
+ MockDrawableContainer container;
+ DrawableContainerState containerState;
+
+ // Empty
+ container = new MockDrawableContainer();
+ containerState = (DrawableContainerState) new LevelListDrawable().getConstantState();
+ assertNotNull(containerState);
+ container.setConstantState(containerState);
+ container.setState(FOCUSED_STATE);
+ assertFalse(container.hasFocusStateSpecified());
+
+ // No drawable of state_focused=true
+ container = new MockDrawableContainer();
+ containerState = (DrawableContainerState) new LevelListDrawable().getConstantState();
+ assertNotNull(containerState);
+ container.setConstantState(containerState);
+ containerState.addChild(DrawableFactory.createPaintDrawable());
+ containerState.addChild(DrawableFactory.createBitmapDrawable(mContext));
+ containerState.addChild(DrawableFactory.createColorDrawable());
+ container.selectDrawable(0);
+ container.setState(FOCUSED_STATE);
+ assertFalse(container.hasFocusStateSpecified());
+ container.selectDrawable(1);
+ container.setState(FOCUSED_STATE);
+ assertFalse(container.hasFocusStateSpecified());
+ container.selectDrawable(2);
+ container.setState(FOCUSED_STATE);
+ assertFalse(container.hasFocusStateSpecified());
+
+ // Only drawables of state_focused=true
+ container = new MockDrawableContainer();
+ containerState = (DrawableContainerState) new LevelListDrawable().getConstantState();
+ assertNotNull(containerState);
+ container.setConstantState(containerState);
+ containerState.addChild(DrawableFactory.createRippleDrawable());
+ containerState.addChild(
+ DrawableFactory.createStateListDrawable(
+ new int[][] { STATE_FOCUSED_WITH_POS, STATE_FOCUSED_WITH_NEG }
+ )
+ );
+ container.selectDrawable(0);
+ container.setState(FOCUSED_STATE);
+ assertTrue(container.hasFocusStateSpecified());
+ container.selectDrawable(1);
+ container.setState(FOCUSED_STATE);
+ assertTrue(container.hasFocusStateSpecified());
+
+ // Both drawables of state_focused=true and state_focused=false
+ containerState.addChild(DrawableFactory.createColorDrawable());
+ container.selectDrawable(2);
+ container.setState(FOCUSED_STATE);
+ assertFalse(container.hasFocusStateSpecified());
+ container.selectDrawable(1);
+ container.setState(FOCUSED_STATE);
+ assertTrue(container.hasFocusStateSpecified());
+ container.selectDrawable(0);
+ container.setState(FOCUSED_STATE);
+ assertTrue(container.hasFocusStateSpecified());
+ }
+
+ static class DrawableFactory {
+ static ShapeDrawable createShapeDrawable() {
+ return new ShapeDrawable(new RectShape());
+ }
+ static PaintDrawable createPaintDrawable() {
+ PaintDrawable paintDrawable = new PaintDrawable();
+ paintDrawable.setCornerRadius(1.5f);
+ return paintDrawable;
+ }
+ static BitmapDrawable createBitmapDrawable(Context context) {
+ Bitmap bitmap = Bitmap.createBitmap(200, 300, Config.ARGB_8888);
+ BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), bitmap);
+ return bitmapDrawable;
+ }
+ static ColorDrawable createColorDrawable() {
+ return new ColorDrawable(A_COLOR);
+ }
+ static GradientDrawable createGradientDrawable() {
+ GradientDrawable gradientDrawable = new GradientDrawable();
+ gradientDrawable.setColor(A_COLOR);
+ gradientDrawable.setCornerRadius(10f);
+ return gradientDrawable;
+ }
+ static NinePatchDrawable createNinePatchDrawable(Context context) {
+ Resources res = context.getResources();
+ Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.ninepatch_0);
+ NinePatch np = new NinePatch(bitmap, bitmap.getNinePatchChunk(), null);
+ NinePatchDrawable ninePatchDrawable = new NinePatchDrawable(res, np);
+ return ninePatchDrawable;
+ }
+ static RippleDrawable createRippleDrawable() {
+ RippleDrawable rippleDrawable =
+ new RippleDrawable(ColorStateList.valueOf(A_COLOR), null, null);
+ return rippleDrawable;
+ }
+ static PictureDrawable createPictureDrawable(Picture picture) {
+ PictureDrawable pictureDrawable = new PictureDrawable(picture);
+ return pictureDrawable;
+ }
+ static StateListDrawable createStateListDrawable(int[][] stateList) {
+ StateListDrawable drawable = new StateListDrawable();
+ ColorDrawable colorDrawable = DrawableFactory.createColorDrawable();
+ for (int i = 0; i < stateList.length; i++) {
+ drawable.addState(stateList[i], colorDrawable);
+ }
+ return drawable;
+ }
+ }
+
+ // We're calling protected methods in DrawableContainer.
+ // So we have to extend it here to make it accessible.
+ private class MockDrawableContainer extends DrawableContainer {
+ @Override
+ protected void setConstantState(DrawableContainerState state) {
+ super.setConstantState(state);
+ }
+ }
+
+}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index eb660f3..b798fb8 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -52,6 +52,7 @@
import java.io.IOException;
import java.util.Arrays;
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class GradientDrawableTest {
private Resources mResources;
@@ -61,7 +62,6 @@
mResources = InstrumentationRegistry.getTargetContext().getResources();
}
- @SmallTest
@Test
public void testConstructor() {
int[] color = new int[] {1, 2, 3};
@@ -71,7 +71,6 @@
new GradientDrawable(null, null);
}
- @SmallTest
@Test
public void testGetOpacity() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -105,7 +104,6 @@
}
- @SmallTest
@Test
public void testSetOrientation() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -117,7 +115,6 @@
orientation, gradientDrawable.getOrientation());
}
- @SmallTest
@Test
public void testSetCornerRadii() {
float[] radii = new float[] {1.0f, 2.0f, 3.0f};
@@ -136,7 +133,6 @@
gradientDrawable.setCornerRadii(null);
}
- @SmallTest
@Test
public void testSetCornerRadius() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -145,7 +141,6 @@
gradientDrawable.setCornerRadius(-2.5f);
}
- @SmallTest
@Test
public void testGetCornerRadius() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -160,7 +155,6 @@
assertEquals(0, gradientDrawable.getCornerRadius(), 0);
}
- @SmallTest
@Test
public void testSetStroke() {
helpTestSetStroke(2, Color.RED);
@@ -174,7 +168,6 @@
// TODO: Verify stroke properties.
}
- @SmallTest
@Test
public void testSetStroke_WidthGap() {
verifySetStroke_WidthGap(2, Color.RED, 3.4f, 5.5f);
@@ -189,7 +182,6 @@
// TODO: Verify stroke properties.
}
- @SmallTest
@Test
public void testSetStrokeList() {
verifySetStrokeList(2, ColorStateList.valueOf(Color.RED));
@@ -204,7 +196,6 @@
// TODO: Verify stroke properties.
}
- @SmallTest
@Test
public void testSetStrokeList_WidthGap() {
verifySetStrokeList_WidthGap(2, ColorStateList.valueOf(Color.RED), 3.4f, 5.5f);
@@ -219,7 +210,6 @@
// TODO: Verify stroke properties.
}
- @SmallTest
@Test
public void testSetSize() {
verifySetSize(6, 4);
@@ -235,7 +225,6 @@
assertEquals(height, gradientDrawable.getIntrinsicHeight());
}
- @SmallTest
@Test
public void testSetShape() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -252,7 +241,6 @@
shape, gradientDrawable.getShape());
}
- @SmallTest
@Test
public void testSetGradientType() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -269,7 +257,6 @@
gradientType, gradientDrawable.getGradientType());
}
- @SmallTest
@Test
public void testSetGradientCenter() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -294,7 +281,6 @@
assertEquals(centerY, gradientDrawable.getGradientCenterY(), 0.01f);
}
- @SmallTest
@Test
public void testSetGradientRadius() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -303,7 +289,6 @@
gradientDrawable.setGradientRadius(-3.6f);
}
- @SmallTest
@Test
public void testSetUseLevel() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -322,7 +307,6 @@
useLevel, gradientDrawable.getUseLevel());
}
- @SmallTest
@Test
public void testDraw() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -333,7 +317,6 @@
gradientDrawable.draw(null);
}
- @SmallTest
@Test
public void testSetColor() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -350,7 +333,6 @@
gradientDrawable.getColor().getDefaultColor());
}
- @SmallTest
@Test
public void testSetColors() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -367,7 +349,6 @@
colors, gradientDrawable.getColors());
}
- @SmallTest
@Test
public void testSetColorList() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -382,7 +363,6 @@
assertEquals("Color was set to null (TRANSPARENT)", color, gradientDrawable.getColor());
}
- @SmallTest
@Test
public void testGetChangingConfigurations() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -395,7 +375,6 @@
assertEquals(-20, gradientDrawable.getChangingConfigurations());
}
- @SmallTest
@Test
public void testSetAlpha() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -404,7 +383,6 @@
gradientDrawable.setAlpha(-1);
}
- @SmallTest
@Test
public void testSetDither() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -413,7 +391,6 @@
gradientDrawable.setDither(false);
}
- @SmallTest
@Test
public void testSetColorFilter() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -424,7 +401,6 @@
gradientDrawable.setColorFilter(null);
}
- @SmallTest
@Test
public void testInflate() throws XmlPullParserException, IOException {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -469,7 +445,6 @@
}
}
- @SmallTest
@Test
public void testInflateGradientRadius() throws XmlPullParserException, IOException {
Rect parentBounds = new Rect(0, 0, 100, 100);
@@ -490,7 +465,6 @@
assertEquals(50.0f, radius, 0.0f);
}
- @SmallTest
@Test
public void testGetIntrinsicWidth() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -501,7 +475,6 @@
assertEquals(-10, gradientDrawable.getIntrinsicWidth());
}
- @SmallTest
@Test
public void testGetIntrinsicHeight() {
GradientDrawable gradientDrawable = new GradientDrawable();
@@ -512,14 +485,12 @@
assertEquals(-15, gradientDrawable.getIntrinsicHeight());
}
- @SmallTest
@Test
public void testGetConstantState() {
GradientDrawable gradientDrawable = new GradientDrawable();
assertNotNull(gradientDrawable.getConstantState());
}
- @SmallTest
@Test
public void testMutate() {
GradientDrawable d1 =
@@ -555,17 +526,28 @@
assertEquals(40, d3.getIntrinsicWidth());
}
- @MediumTest
@Test
public void testPreloadDensity() throws XmlPullParserException, IOException {
final int densityDpi = mResources.getConfiguration().densityDpi;
try {
+ DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
verifyPreloadDensityInner(mResources, densityDpi);
} finally {
DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
}
}
+ @Test
+ public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+ final int densityDpi = mResources.getConfiguration().densityDpi;
+ try {
+ DrawableTestUtils.setResourcesDensity(mResources, 213);
+ verifyPreloadDensityInner(mResources, 213);
+ } finally {
+ DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+ }
+ }
+
private void verifyPreloadDensityInner(Resources res, int densityDpi)
throws XmlPullParserException, IOException {
final Rect tempPadding = new Rect();
@@ -581,15 +563,17 @@
final Rect origPadding = new Rect();
preloadedDrawable.getPadding(origPadding);
- // Set density to half of original. Unlike offsets, which are
+ // Set density to approximately half of original. Unlike offsets, which are
// truncated, dimensions are rounded to the nearest pixel.
DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final GradientDrawable halfDrawable =
(GradientDrawable) preloadedConstantState.newDrawable(res);
- assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
- assertEquals(Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+ // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+ final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+ assertEquals(Math.round(origWidth * approxHalf), halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(origHeight * approxHalf), halfDrawable.getIntrinsicHeight());
assertTrue(halfDrawable.getPadding(tempPadding));
- assertEquals((int) (origPadding.left / 2f), tempPadding.left);
+ assertEquals((int) (origPadding.left * approxHalf), tempPadding.left);
// Set density to double original.
DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
@@ -609,20 +593,21 @@
assertTrue(origDrawable.getPadding(tempPadding));
assertEquals(origPadding, tempPadding);
- // Some precision is lost when scaling the half-density
- // drawable back up to the original density. Padding is
- // always truncated, rather than rounded.
+ // Reproduce imprecise truncated scale down, and back up. Note these aren't rounded.
+ final float approxDouble = 1 / approxHalf;
final Rect sloppyOrigPadding = new Rect();
- sloppyOrigPadding.left = 2 * (origPadding.left / 2);
- sloppyOrigPadding.top = 2 * (origPadding.top / 2);
- sloppyOrigPadding.right = 2 * (origPadding.right / 2);
- sloppyOrigPadding.bottom = 2 * (origPadding.bottom / 2);
+ sloppyOrigPadding.left = (int)(approxDouble * ((int)(origPadding.left * approxHalf)));
+ sloppyOrigPadding.top = (int)(approxDouble * ((int)(origPadding.top * approxHalf)));
+ sloppyOrigPadding.right = (int)(approxDouble * ((int)(origPadding.right * approxHalf)));
+ sloppyOrigPadding.bottom = (int)(approxDouble * ((int)(origPadding.bottom * approxHalf)));
// Ensure theme density is applied correctly.
final Theme t = res.newTheme();
halfDrawable.applyTheme(t);
- assertEquals(2 * Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
- assertEquals(2 * Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+ assertEquals(Math.round(approxDouble * Math.round(origWidth * approxHalf)),
+ halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(approxDouble * Math.round(origHeight * approxHalf)),
+ halfDrawable.getIntrinsicHeight());
assertTrue(halfDrawable.getPadding(tempPadding));
assertEquals(sloppyOrigPadding, tempPadding);
doubleDrawable.applyTheme(t);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
index 3fcdf82..5eb89fc 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -342,12 +342,25 @@
final Resources res = mContext.getResources();
final int densityDpi = res.getConfiguration().densityDpi;
try {
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
verifyPreloadDensityInner(res, densityDpi);
} finally {
DrawableTestUtils.setResourcesDensity(res, densityDpi);
}
}
+ @Test
+ public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+ final Resources res = mContext.getResources();
+ final int densityDpi = res.getConfiguration().densityDpi;
+ try {
+ DrawableTestUtils.setResourcesDensity(res, 213);
+ verifyPreloadDensityInner(res, 213);
+ } finally {
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
+ }
+ }
+
private void verifyPreloadDensityInner(Resources res, int densityDpi)
throws XmlPullParserException, IOException {
// Capture initial state at default density.
@@ -359,12 +372,14 @@
final int origInsetHoriz = preloadedDrawable.getIntrinsicWidth()
- preloadedDrawable.getDrawable().getIntrinsicWidth();
- // Set density to half of original. Unlike offsets, which are
+ // Set density to approximately half of original. Unlike offsets, which are
// truncated, dimensions are rounded to the nearest pixel.
DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final InsetDrawable halfDrawable =
(InsetDrawable) preloadedConstantState.newDrawable(res);
- assertEquals(Math.round(origInsetHoriz / 2f), halfDrawable.getIntrinsicWidth()
+ // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+ final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+ assertEquals(Math.round(origInsetHoriz * approxHalf), halfDrawable.getIntrinsicWidth()
- halfDrawable.getDrawable().getIntrinsicWidth());
// Set density to double original.
@@ -384,8 +399,10 @@
// Ensure theme density is applied correctly.
final Theme t = res.newTheme();
halfDrawable.applyTheme(t);
- assertEquals(origInsetHoriz, halfDrawable.getIntrinsicWidth()
- - halfDrawable.getDrawable().getIntrinsicWidth());
+ float approxDouble = 1 / approxHalf;
+ // Reproduce imprecise truncated scale down, and back up. Note that we don't round.
+ assertEquals((int)(approxDouble * ((int)(origInsetHoriz * approxHalf))),
+ halfDrawable.getIntrinsicWidth() - halfDrawable.getDrawable().getIntrinsicWidth());
doubleDrawable.applyTheme(t);
assertEquals(origInsetHoriz, doubleDrawable.getIntrinsicWidth()
- doubleDrawable.getDrawable().getIntrinsicWidth());
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index 22491ee..ed9a187 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -1678,12 +1678,25 @@
final Resources res = mContext.getResources();
final int densityDpi = res.getConfiguration().densityDpi;
try {
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
verifyPreloadDensityInner(res, densityDpi);
} finally {
DrawableTestUtils.setResourcesDensity(res, densityDpi);
}
}
+ @Test
+ public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+ final Resources res = mContext.getResources();
+ final int densityDpi = res.getConfiguration().densityDpi;
+ try {
+ DrawableTestUtils.setResourcesDensity(res, 213);
+ verifyPreloadDensityInner(res, 213);
+ } finally {
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
+ }
+ }
+
private void verifyPreloadDensityInner(Resources res, int densityDpi)
throws XmlPullParserException, IOException {
// Capture initial state at default density.
@@ -1714,11 +1727,13 @@
DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final LayerDrawable halfDrawable =
(LayerDrawable) preloadedConstantState.newDrawable(res);
- final int halfContentWidth = Math.round(initialContentWidth / 2f);
- final int halfLeftPadding = initialLeftPadding / 2;
- final int halfRightPadding = initialRightPadding / 2;
- final int halfContentInsetL = initialContentInsetL / 2;
- final int halfContentInsetR = initialContentInsetR / 2;
+ // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+ final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+ final int halfContentWidth = Math.round(initialContentWidth * approxHalf);
+ final int halfLeftPadding = (int) (initialLeftPadding * approxHalf);
+ final int halfRightPadding = (int) (initialRightPadding * approxHalf);
+ final int halfContentInsetL = (int) (initialContentInsetL * approxHalf);
+ final int halfContentInsetR = (int) (initialContentInsetR * approxHalf);
final int halfIntrinsicWidth = halfContentWidth + halfContentInsetL + halfContentInsetR;
assertEquals(halfLeftPadding, halfDrawable.getLeftPadding());
assertEquals(halfRightPadding, halfDrawable.getRightPadding());
@@ -1726,14 +1741,18 @@
assertEquals(halfContentInsetR, halfDrawable.getLayerInsetLeft(0));
assertEquals(halfContentWidth, halfDrawable.getLayerWidth(0));
assertEquals(halfIntrinsicWidth, halfDrawable.getIntrinsicWidth());
- assertEquals(initialBottomPadding / 2, halfDrawable.getBottomPadding());
- assertEquals(initialTopPadding / 2, halfDrawable.getTopPadding());
- assertEquals(initialLayerInsetLeft / 2,halfDrawable.getLayerInsetLeft(0));
- assertEquals(initialLayerInsetRight / 2, halfDrawable.getLayerInsetRight(0));
- assertEquals(initialLayerInsetTop / 2, halfDrawable.getLayerInsetTop(0));
- assertEquals(initialLayerInsetBottom / 2, halfDrawable.getLayerInsetBottom(0));
- assertEquals(Math.round(initialLayerWidth / 2f), halfDrawable.getLayerWidth(0));
- assertEquals(Math.round(initialLayerHeight / 2f), halfDrawable.getLayerHeight(0));
+ assertEquals((int) (initialBottomPadding * approxHalf), halfDrawable.getBottomPadding());
+ assertEquals((int) (initialTopPadding * approxHalf), halfDrawable.getTopPadding());
+ assertEquals((int) (initialLayerInsetLeft * approxHalf),
+ halfDrawable.getLayerInsetLeft(0));
+ assertEquals((int) (initialLayerInsetRight * approxHalf),
+ halfDrawable.getLayerInsetRight(0));
+ assertEquals((int) (initialLayerInsetTop * approxHalf),
+ halfDrawable.getLayerInsetTop(0));
+ assertEquals((int) (initialLayerInsetBottom * approxHalf),
+ halfDrawable.getLayerInsetBottom(0));
+ assertEquals(Math.round(initialLayerWidth * approxHalf), halfDrawable.getLayerWidth(0));
+ assertEquals(Math.round(initialLayerHeight * approxHalf), halfDrawable.getLayerHeight(0));
// Set density to double original.
DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
@@ -1779,20 +1798,31 @@
// The half-density drawable will scale-up all of the values that were
// previously scaled-down, so we need to capture the rounding errors.
halfDrawable.applyTheme(t);
- assertEquals(halfLeftPadding * 2, halfDrawable.getLeftPadding());
- assertEquals(halfRightPadding * 2, halfDrawable.getRightPadding());
- assertEquals(halfContentInsetL * 2, halfDrawable.getLayerInsetRight(0));
- assertEquals(halfContentInsetR * 2, halfDrawable.getLayerInsetLeft(0));
- assertEquals(halfContentWidth * 2, halfDrawable.getLayerWidth(0));
+
+ // Reproduce imprecise truncated scale down, and back up. Note that we don't round.
+ float approxDouble = 1 / approxHalf;
+ assertEquals((int) (halfLeftPadding * approxDouble), halfDrawable.getLeftPadding());
+ assertEquals((int) (halfRightPadding * approxDouble), halfDrawable.getRightPadding());
+ assertEquals((int) (halfContentInsetL * approxDouble), halfDrawable.getLayerInsetRight(0));
+ assertEquals((int) (halfContentInsetR * approxDouble), halfDrawable.getLayerInsetLeft(0));
+ assertEquals((int) (halfContentWidth * approxDouble), halfDrawable.getLayerWidth(0));
assertEquals(halfIntrinsicWidth * 2, halfDrawable.getIntrinsicWidth());
- assertEquals(2 * (initialBottomPadding / 2), halfDrawable.getBottomPadding());
- assertEquals(2 * (initialTopPadding / 2), halfDrawable.getTopPadding());
- assertEquals(2 * (initialLayerInsetLeft / 2), halfDrawable.getLayerInsetLeft(0));
- assertEquals(2 * (initialLayerInsetRight / 2), halfDrawable.getLayerInsetRight(0));
- assertEquals(2 * (initialLayerInsetTop / 2), halfDrawable.getLayerInsetTop(0));
- assertEquals(2 * (initialLayerInsetBottom / 2), halfDrawable.getLayerInsetBottom(0));
- assertEquals(2 * Math.round(initialLayerWidth / 2f), halfDrawable.getLayerWidth(0));
- assertEquals(2 * Math.round(initialLayerHeight / 2f), halfDrawable.getLayerHeight(0));
+ assertEquals((int) ((int) (initialBottomPadding * approxHalf) * approxDouble),
+ halfDrawable.getBottomPadding());
+ assertEquals((int) ((int) (initialTopPadding * approxHalf) * approxDouble),
+ halfDrawable.getTopPadding());
+ assertEquals((int) ((int) (initialLayerInsetLeft * approxHalf) * approxDouble),
+ halfDrawable.getLayerInsetLeft(0));
+ assertEquals((int) ((int) (initialLayerInsetRight * approxHalf) * approxDouble),
+ halfDrawable.getLayerInsetRight(0));
+ assertEquals((int) ((int) (initialLayerInsetTop * approxHalf) * approxDouble),
+ halfDrawable.getLayerInsetTop(0));
+ assertEquals((int) ((int) (initialLayerInsetBottom * approxHalf) * approxDouble),
+ halfDrawable.getLayerInsetBottom(0));
+ assertEquals(Math.round(Math.round(initialLayerWidth * approxHalf) * approxDouble),
+ halfDrawable.getLayerWidth(0));
+ assertEquals(Math.round(Math.round(initialLayerHeight * approxHalf) * approxDouble),
+ halfDrawable.getLayerHeight(0));
// The double-density drawable will scale-down all of the values that
// were previously scaled-up, so we don't need to worry about rounding.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 80d604e..d563102 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -36,6 +36,7 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.cts.R;
@@ -219,6 +220,18 @@
assertNull(shapeDrawable.getShaderFactory());
}
+ @Test
+ public void testSetXfermode() {
+ ShapeDrawable shapeDrawable = new ShapeDrawable();
+
+ PorterDuffXfermode xfermode = new PorterDuffXfermode(Mode.SRC_OVER);
+ shapeDrawable.setXfermode(xfermode);
+ assertSame(xfermode, shapeDrawable.getPaint().getXfermode());
+
+ shapeDrawable.setXfermode(null);
+ assertNull(shapeDrawable.getPaint().getXfermode());
+ }
+
public static class MockShaderFactory extends ShaderFactory {
public Shader resize(int width, int height) {
return null;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
index fb3445e..6499594 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
@@ -229,10 +229,12 @@
DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final StateListDrawable halfDrawable =
(StateListDrawable) preloadedConstantState.newDrawable(res);
+ // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+ final float approxHalf = (float)(densityDpi / 2) / densityDpi;
halfDrawable.selectDrawable(0);
- assertEquals(Math.round(origWidth0 / 2f), halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(origWidth0 * approxHalf), halfDrawable.getIntrinsicWidth());
halfDrawable.selectDrawable(1);
- assertEquals(Math.round(origWidth1 / 2f), halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(origWidth1 * approxHalf), halfDrawable.getIntrinsicWidth());
// Set density to double original.
DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
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 16c6961..276bf50 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -33,7 +33,6 @@
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.VectorDrawable;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.AttributeSet;
@@ -50,6 +49,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class VectorDrawableTest {
private static final String LOGTAG = "VectorDrawableTest";
@@ -200,31 +200,26 @@
mResources = InstrumentationRegistry.getTargetContext().getResources();
}
- @MediumTest
@Test
public void testBasicVectorDrawables() throws XmlPullParserException, IOException {
verifyVectorDrawables(BASIC_ICON_RES_IDS, BASIC_GOLDEN_IMAGES, null);
}
- @MediumTest
@Test
public void testLMVectorDrawables() throws XmlPullParserException, IOException {
verifyVectorDrawables(L_M_ICON_RES_IDS, L_M_GOLDEN_IMAGES, null);
}
- @MediumTest
@Test
public void testNVectorDrawables() throws XmlPullParserException, IOException {
verifyVectorDrawables(N_ICON_RES_IDS, N_GOLDEN_IMAGES, null);
}
- @MediumTest
@Test
public void testVectorDrawableGradient() throws XmlPullParserException, IOException {
verifyVectorDrawables(GRADIENT_ICON_RES_IDS, GRADIENT_GOLDEN_IMAGES, null);
}
- @MediumTest
@Test
public void testColorStateList() throws XmlPullParserException, IOException {
for (int i = 0; i < STATEFUL_STATE_SETS.length; i++) {
@@ -344,7 +339,6 @@
return builder.toString();
}
- @SmallTest
@Test
public void testGetChangingConfigurations() {
VectorDrawable vectorDrawable = new VectorDrawable();
@@ -369,7 +363,6 @@
assertEquals(0xffff, vectorDrawable.getChangingConfigurations());
}
- @SmallTest
@Test
public void testGetConstantState() {
VectorDrawable vectorDrawable = new VectorDrawable();
@@ -383,7 +376,6 @@
assertEquals(1, constantState.getChangingConfigurations());
}
- @SmallTest
@Test
public void testMutate() {
// d1 and d2 will be mutated, while d3 will not.
@@ -419,7 +411,6 @@
}
}
- @SmallTest
@Test
public void testColorFilter() {
PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, Mode.SRC_IN);
@@ -429,18 +420,6 @@
assertEquals(filter, vectorDrawable.getColorFilter());
}
- @SmallTest
- @Test
- public void testPreloadDensity() throws XmlPullParserException, IOException {
- final int densityDpi = mResources.getConfiguration().densityDpi;
- try {
- verifyPreloadDensityInner(mResources, densityDpi);
- } finally {
- DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
- }
- }
-
- @SmallTest
@Test
public void testGetOpacity () throws XmlPullParserException, IOException {
VectorDrawable vectorDrawable = new VectorDrawable();
@@ -455,6 +434,28 @@
vectorDrawable.getOpacity());
}
+ @Test
+ public void testPreloadDensity() throws XmlPullParserException, IOException {
+ final int densityDpi = mResources.getConfiguration().densityDpi;
+ try {
+ DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+ verifyPreloadDensityInner(mResources, densityDpi);
+ } finally {
+ DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+ }
+ }
+
+ @Test
+ public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+ final int densityDpi = mResources.getConfiguration().densityDpi;
+ try {
+ DrawableTestUtils.setResourcesDensity(mResources, 213);
+ verifyPreloadDensityInner(mResources, 213);
+ } finally {
+ DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+ }
+ }
+
private void verifyPreloadDensityInner(Resources res, int densityDpi)
throws XmlPullParserException, IOException {
// Capture initial state at default density.
@@ -470,7 +471,9 @@
DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final VectorDrawable halfDrawable =
(VectorDrawable) preloadedConstantState.newDrawable(res);
- assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+ // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+ final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+ assertEquals(Math.round(origWidth * approxHalf), halfDrawable.getIntrinsicWidth());
// Set density to double original.
DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 3b890f2..16a202e 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -71,11 +71,14 @@
}
static bool already_loaded(const std::string& library, const std::string& err) {
- if (err.find("dlopen failed: library \"" + library + "\"") != 0 ||
- err.find("is not accessible for the namespace \"classloader-namespace\"") == std::string::npos) {
- return false;
+ // SELinux denials for /vendor libraries may return with library not found
+ if (err.find("dlopen failed: library \"" + library + "\"") == 0 &&
+ (err.find("not found") != std::string::npos ||
+ err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos)) {
+ return true;
}
- return true;
+
+ return false;
}
static bool check_lib(const std::string& path,
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 8bfd79b..b7f7c8e 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -56,6 +56,7 @@
import android.os.SystemProperties;
import android.security.KeyStoreException;
import android.security.keystore.AttestationUtils;
+import android.security.keystore.DeviceIdAttestationException;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.test.AndroidTestCase;
@@ -108,6 +109,7 @@
.compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+ private static final int KM_ERROR_PERMISSION_DENIED = 6;
public void testVersionParser() throws Exception {
// Non-numerics/empty give version 0
@@ -210,6 +212,29 @@
}
}
+ public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
+ String keystoreAlias = "test_key";
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
+ .setAttestationChallenge(new byte[128])
+ .setUniqueIdIncluded(true)
+ .build();
+
+ try {
+ generateKeyPair(KEY_ALGORITHM_EC, spec);
+ fail("Attestation should have failed.");
+ } catch (ProviderException e) {
+ // Attestation is expected to fail because of lack of permissions.
+ KeyStoreException cause = (KeyStoreException) e.getCause();
+ assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode());
+ } finally {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ keyStore.deleteEntry(keystoreAlias);
+ }
+ }
+
public void testRsaAttestation() throws Exception {
int[] keySizes = { // Smallish sizes to keep test runtimes down.
512, 768, 1024
@@ -357,9 +382,9 @@
}
public void testDeviceIdAttestation() throws Exception {
- testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL);
- testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI);
- testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID);
+ testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null);
+ testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI");
+ testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID");
}
@SuppressWarnings("deprecation")
@@ -855,13 +880,23 @@
}
}
- private void testDeviceIdAttestationFailure(int idType) throws Exception {
+ private void testDeviceIdAttestationFailure(int idType,
+ String acceptableDeviceIdAttestationFailureMessage) throws Exception {
try {
AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes());
fail("Attestation should have failed.");
} catch (SecurityException e) {
- // Attestation is expected to fail with a SecurityException as we do not hold
+ // Attestation is expected to fail. If the device has the device ID type we are trying
+ // to attest, it should fail with a SecurityException as we do not hold
// READ_PRIVILEGED_PHONE_STATE permission.
+ } catch (DeviceIdAttestationException e) {
+ // Attestation is expected to fail. If the device does not have the device ID type we
+ // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with
+ // a corresponding DeviceIdAttestationException.
+ if (acceptableDeviceIdAttestationFailureMessage == null ||
+ !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) {
+ throw e;
+ }
}
}
}
diff --git a/tests/tests/location/src/android/location/cts/LocationTest.java b/tests/tests/location/src/android/location/cts/LocationTest.java
index 18faaee..3e291cf 100644
--- a/tests/tests/location/src/android/location/cts/LocationTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationTest.java
@@ -36,6 +36,9 @@
public class LocationTest extends AndroidTestCase {
private static final float DELTA = 0.1f;
private final float TEST_ACCURACY = 1.0f;
+ private final float TEST_VERTICAL_ACCURACY = 2.0f;
+ private final float TEST_SPEED_ACCURACY = 3.0f;
+ private final float TEST_BEARING_ACCURACY = 4.0f;
private final double TEST_ALTITUDE = 1.0;
private final double TEST_LATITUDE = 50;
private final float TEST_BEARING = 1.0f;
@@ -51,6 +54,7 @@
private static final String ENABLED_KEY = "enabled";
private static final String MESSENGER_KEY = "messenger";
+
public void testConstructor() {
new Location("LocationProvider");
@@ -271,6 +275,34 @@
assertFalse(location.hasAccuracy());
}
+ public void testAccessVerticalAccuracy() {
+ Location location = new Location("");
+ assertFalse(location.hasVerticalAccuracy());
+
+ location.setVerticalAccuracyMeters(1.0f);
+ assertEquals(1.0, location.getVerticalAccuracyMeters(), DELTA);
+ assertTrue(location.hasVerticalAccuracy());
+ }
+
+ public void testAccessSpeedAccuracy() {
+ Location location = new Location("");
+ assertFalse(location.hasSpeedAccuracy());
+
+ location.setSpeedAccuracyMetersPerSecond(1.0f);
+ assertEquals(1.0, location.getSpeedAccuracyMetersPerSecond(), DELTA);
+ assertTrue(location.hasSpeedAccuracy());
+ }
+
+ public void testAccessBearingAccuracy() {
+ Location location = new Location("");
+ assertFalse(location.hasBearingAccuracy());
+
+ location.setBearingAccuracyDegrees(1.0f);
+ assertEquals(1.0, location.getBearingAccuracyDegrees(), DELTA);
+ assertTrue(location.hasBearingAccuracy());
+ }
+
+
public void testAccessAltitude() {
Location location = new Location("");
assertFalse(location.hasAltitude());
@@ -411,6 +443,15 @@
assertFalse(location.hasBearing());
assertEquals(0, location.getAccuracy(), DELTA);
assertFalse(location.hasAccuracy());
+
+ assertEquals(0, location.getVerticalAccuracyMeters(), DELTA);
+ assertEquals(0, location.getSpeedAccuracyMetersPerSecond(), DELTA);
+ assertEquals(0, location.getBearingAccuracyDegrees(), DELTA);
+
+ assertFalse(location.hasVerticalAccuracy());
+ assertFalse(location.hasSpeedAccuracy());
+ assertFalse(location.hasBearingAccuracy());
+
assertNull(location.getExtras());
}
@@ -486,6 +527,9 @@
assertNotNull(l);
assertEquals(TEST_PROVIDER, l.getProvider());
assertEquals(TEST_ACCURACY, l.getAccuracy(), DELTA);
+ assertEquals(TEST_VERTICAL_ACCURACY, l.getVerticalAccuracyMeters(), DELTA);
+ assertEquals(TEST_SPEED_ACCURACY, l.getSpeedAccuracyMetersPerSecond(), DELTA);
+ assertEquals(TEST_BEARING_ACCURACY, l.getBearingAccuracyDegrees(), DELTA);
assertEquals(TEST_ALTITUDE, l.getAltitude(), DELTA);
assertEquals(TEST_LATITUDE, l.getLatitude(), DELTA);
assertEquals(TEST_BEARING, l.getBearing(), DELTA);
@@ -498,6 +542,10 @@
private Location createTestLocation() {
Location l = new Location(TEST_PROVIDER);
l.setAccuracy(TEST_ACCURACY);
+ l.setVerticalAccuracyMeters(TEST_VERTICAL_ACCURACY);
+ l.setSpeedAccuracyMetersPerSecond(TEST_SPEED_ACCURACY);
+ l.setBearingAccuracyDegrees(TEST_BEARING_ACCURACY);
+
l.setAltitude(TEST_ALTITUDE);
l.setLatitude(TEST_LATITUDE);
l.setBearing(TEST_BEARING);
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordConcurrencyTest.java b/tests/tests/media/src/android/media/cts/AudioRecordConcurrencyTest.java
deleted file mode 100644
index 07d7290..0000000
--- a/tests/tests/media/src/android/media/cts/AudioRecordConcurrencyTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2017 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.pm.PackageManager;
-import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioRecord;
-import android.media.MediaRecorder;
-import android.media.AudioRecordingConfiguration;
-import android.util.Log;
-
-import com.android.compatibility.common.util.CtsAndroidTestCase;
-
-import java.util.List;
-
-public class AudioRecordConcurrencyTest extends CtsAndroidTestCase {
- static final String TAG = "AudioRecordConcurrencyTest";
- static final String REPORT_LOG_NAME = "CtsMediaTestCases";
- static final int RECORD_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
- static final int RECORD_CHANNEL_MASK = AudioFormat.CHANNEL_IN_MONO;
- static final int RECORD_SAMPLE_RATE = 16000;
- static final long SLEEP_AFTER_STOP_FOR_INACTIVITY_MS = 1000;
- static final int TEST_TIMING_TOLERANCE_MS = 70;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- if (!hasMicrophone()) {
- Log.i(TAG, "AudioRecordConcurrencyTest skipped: no microphone");
- return;
- }
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- public void testConcurrentRecord() throws Exception {
- final String TEST_NAME = "testConcurrentRecord";
-
- if (!hasMicrophone()) {
- Log.i(TAG, "testConcurrentRecord() skipped: no microphone");
- return;
- }
-
- int[] foregroundSources = new int[] {
- MediaRecorder.AudioSource.MIC,
- MediaRecorder.AudioSource.CAMCORDER,
- MediaRecorder.AudioSource.VOICE_COMMUNICATION,
- };
-
- int[] backgroundSources = new int[] {
- MediaRecorder.AudioSource.VOICE_RECOGNITION,
- };
-
- for (int source1 : backgroundSources) {
- for (int source2 : backgroundSources) {
- assertTrue(TEST_NAME+" failed background source: "+source1+
- " background source: "+source2,
- doConcurrencyTest(TEST_NAME, source1, source2));
- }
- }
-
- for (int source1 : backgroundSources) {
- for (int source2 : foregroundSources) {
- assertTrue(TEST_NAME+" failed background source: "+source1+
- " foreground source: "+source2,
- doConcurrencyTest(TEST_NAME, source1, source2));
- }
- }
-
- for (int source1 : foregroundSources) {
- for (int source2 : backgroundSources) {
- assertTrue(TEST_NAME+" failed foreground source: "+source1+
- " background source: "+source2,
- doConcurrencyTest(TEST_NAME, source1, source2));
- }
- }
-
- for (int source1 : foregroundSources) {
- for (int source2 : foregroundSources) {
- assertFalse(TEST_NAME+" failed foreground: "+ source1+
- " foreground source: "+ source2,
- doConcurrencyTest(TEST_NAME, source1, source2));
- }
- }
- }
-
- boolean doConcurrencyTest(String testName, int source1, int source2) {
- AudioRecord record1 = null;
- AudioRecord record2 = null;
- boolean active1 = false;
- boolean active2 = false;
-
- try {
-
- AudioFormat format = new AudioFormat.Builder()
- .setSampleRate(RECORD_SAMPLE_RATE)
- .setChannelMask(RECORD_CHANNEL_MASK)
- .setEncoding(RECORD_ENCODING)
- .build();
-
- record1 = new AudioRecord.Builder()
- .setAudioSource(source1)
- .setAudioFormat(format)
- .build();
- // AudioRecord creation may have silently failed, check state now
- assertEquals(testName, AudioRecord.STATE_INITIALIZED, record1.getState());
-
- record2 = new AudioRecord.Builder()
- .setAudioSource(source2)
- .setAudioFormat(format)
- .build();
- // AudioRecord creation may have silently failed, check state now
- assertEquals(testName, AudioRecord.STATE_INITIALIZED, record2.getState());
-
- final int BUFFER_FRAMES = 512;
- final int BUFFER_SAMPLES = BUFFER_FRAMES * format.getChannelCount();
-
- short[] shortData = new short[BUFFER_SAMPLES];
-
- record1.startRecording();
- record2.startRecording();
- try {
- Thread.sleep(TEST_TIMING_TOLERANCE_MS);
- } catch (InterruptedException e) {
- }
- if (record1.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
- int ret = record1.read(shortData, 0, BUFFER_SAMPLES);
- active1 = ret == BUFFER_SAMPLES;
- }
- if (record2.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
- int ret = record2.read(shortData, 0, BUFFER_SAMPLES);
- active2 = ret == BUFFER_SAMPLES;
- }
-
- if (active1 && active2) {
- // verify we have at least 2 active recording configurations
- AudioManager am = new AudioManager(getContext());
- assertNotNull("Could not create AudioManager", am);
- List<AudioRecordingConfiguration> configs = am.getActiveRecordingConfigurations();
- assertNotNull("Invalid null array of record configurations during recording",
- configs);
- assertTrue("no active record configurations (empty array) during recording",
- configs.size() > 1);
- }
-
- record2.stop();
- record1.stop();
- } finally {
- if (record1 != null) {
- record1.release();
- }
- if (record2 != null) {
- record2.release();
- }
- // wait for stop to be completed at audio flinger level
- try {
- Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
- } catch (InterruptedException e) {
- }
- }
- return active1 && active2;
- }
-
- private boolean hasMicrophone() {
- return getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_MICROPHONE);
- }
-}
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index efe8bb4..61edbba 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -36,12 +36,13 @@
import java.util.List;
public class AudioRecordingConfigurationTest extends CtsAndroidTestCase {
- private final static String TAG = "AudioRecordingConfigurationTest";
+ private static final String TAG = "AudioRecordingConfigurationTest";
- private final static int TEST_SAMPLE_RATE = 16000;
- private final static int TEST_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
+ private static final int TEST_SAMPLE_RATE = 16000;
+ private static final int TEST_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
- private final static int TEST_TIMING_TOLERANCE_MS = 70;
+ private static final int TEST_TIMING_TOLERANCE_MS = 70;
+ private static final long SLEEP_AFTER_STOP_FOR_INACTIVITY_MS = 1000;
private AudioRecord mAudioRecord;
private Looper mLooper;
@@ -93,6 +94,7 @@
mAudioRecord.stop();
mAudioRecord.release();
mLooper.quit();
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
}
super.tearDown();
}
@@ -127,10 +129,10 @@
// stopping recording: verify there are less active record configurations
mAudioRecord.stop();
- Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
configs = am.getActiveRecordingConfigurations();
- assertTrue("end of recording not reported in record configs",
- configs.size() < nbConfigsDuringRecording);
+ assertEquals("Unexpected number of recording configs after stop",
+ configs.size(), 0);
}
public void testCallback() throws Exception {
@@ -169,15 +171,23 @@
assertEquals(AudioRecord.RECORDSTATE_RECORDING, mAudioRecord.getRecordingState());
Thread.sleep(TEST_TIMING_TOLERANCE_MS);
- assertTrue("AudioRecordingCallback not called", callback.mCalled);
- assertTrue("Expected record configuration was not found", callback.mParamMatch);
+ assertTrue("AudioRecordingCallback not called after start", callback.mCalled);
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+
+ final AudioDeviceInfo testDevice = mAudioRecord.getRoutedDevice();
+ assertTrue("AudioRecord null routed device after start", testDevice != null);
+ final boolean match = verifyAudioConfig(mAudioRecord.getAudioSource(),
+ mAudioRecord.getAudioSessionId(), mAudioRecord.getFormat(),
+ testDevice, callback.mConfigs);
+ assertTrue("Expected record configuration was not found", match);
// stopping recording: callback is called with no match
callback.reset();
mAudioRecord.stop();
- Thread.sleep(TEST_TIMING_TOLERANCE_MS);
- assertTrue("AudioRecordingCallback not called", callback.mCalled);
- assertFalse("Should not have found test record configuration", callback.mParamMatch);
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
+ assertTrue("AudioRecordingCallback not called after stop", callback.mCalled);
+ assertEquals("Should not have found record configurations", callback.mConfigs.size(),
+ 0);
// unregister callback and start recording again
am.unregisterAudioRecordingCallback(callback);
@@ -231,14 +241,14 @@
class MyAudioRecordingCallback extends AudioManager.AudioRecordingCallback {
boolean mCalled = false;
- boolean mParamMatch = false;
+ List<AudioRecordingConfiguration> mConfigs;
final AudioManager mAM;
final int mTestSource;
final int mTestSession;
void reset() {
mCalled = false;
- mParamMatch = false;
+ mConfigs = null;
}
MyAudioRecordingCallback(int session, int source) {
@@ -250,8 +260,7 @@
@Override
public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
mCalled = true;
- mParamMatch = verifyAudioConfig(mTestSource, mTestSession, mAudioRecord.getFormat(),
- mAudioRecord.getRoutedDevice(), configs);
+ mConfigs = configs;
}
}
@@ -266,6 +275,8 @@
final Iterator<AudioRecordingConfiguration> confIt = configs.iterator();
while (confIt.hasNext()) {
final AudioRecordingConfiguration config = confIt.next();
+ final AudioDeviceInfo configDevice = config.getAudioDevice();
+ assertTrue("Current recording config has null device", configDevice != null);
if ((config.getClientAudioSource() == source)
&& (config.getClientAudioSessionId() == session)
// test the client format matches that requested (same as the AudioRecord's)
@@ -281,7 +292,7 @@
&& ((config.getFormat().getChannelMask() != AudioFormat.CHANNEL_INVALID)
|| (config.getFormat().getChannelIndexMask() !=
AudioFormat.CHANNEL_INVALID))
- && deviceMatch(device, config.getAudioDevice())) {
+ && deviceMatch(device, configDevice)) {
return true;
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 0cbbe7e..99c0ac1 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -36,13 +36,63 @@
"android.media.cts", "android.media.cts.StubMediaBrowserService");
private final Object mWaitLock = new Object();
- private final ConnectionCallback mConnectionCallback = new ConnectionCallback();
- private final SubscriptionCallback mSubscriptionCallback = new SubscriptionCallback();
- private final ItemCallback mItemCallback = new ItemCallback();
- private final SearchCallback mSearchCallback = new SearchCallback();
+ private final MediaBrowser.ConnectionCallback mConnectionCallback =
+ new MediaBrowser.ConnectionCallback() {
+ @Override
+ public void onConnected() {
+ synchronized (mWaitLock) {
+ mMediaBrowserService = StubMediaBrowserService.sInstance;
+ mWaitLock.notify();
+ }
+ }
+ };
+
+ private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
+ new MediaBrowser.SubscriptionCallback() {
+ @Override
+ public void onChildrenLoaded(String parentId, List<MediaItem> children) {
+ synchronized (mWaitLock) {
+ mOnChildrenLoaded = true;
+ if (children != null) {
+ for (MediaItem item : children) {
+ assertRootHints(item);
+ }
+ }
+ mWaitLock.notify();
+ }
+ }
+
+ @Override
+ public void onChildrenLoaded(String parentId, List<MediaItem> children,
+ Bundle options) {
+ synchronized (mWaitLock) {
+ mOnChildrenLoadedWithOptions = true;
+ if (children != null) {
+ for (MediaItem item : children) {
+ assertRootHints(item);
+ }
+ }
+ mWaitLock.notify();
+ }
+ }
+ };
+
+ private final MediaBrowser.ItemCallback mItemCallback = new MediaBrowser.ItemCallback() {
+ @Override
+ public void onItemLoaded(MediaItem item) {
+ synchronized (mWaitLock) {
+ mOnItemLoaded = true;
+ assertRootHints(item);
+ mWaitLock.notify();
+ }
+ }
+ };
private MediaBrowser mMediaBrowser;
private StubMediaBrowserService mMediaBrowserService;
+ private boolean mOnChildrenLoaded;
+ private boolean mOnChildrenLoadedWithOptions;
+ private boolean mOnItemLoaded;
private Bundle mRootHints;
@Override
@@ -72,15 +122,14 @@
public void testNotifyChildrenChanged() throws Exception {
synchronized (mWaitLock) {
- mSubscriptionCallback.reset();
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+ assertTrue(mOnChildrenLoaded);
- mSubscriptionCallback.reset();
+ mOnChildrenLoaded = false;
mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+ assertTrue(mOnChildrenLoaded);
}
}
@@ -92,54 +141,53 @@
options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
options.putInt(MediaBrowser.EXTRA_PAGE, page);
- mSubscriptionCallback.reset();
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
mSubscriptionCallback);
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoadedWithOptions);
+ assertTrue(mOnChildrenLoadedWithOptions);
- mSubscriptionCallback.reset();
+ mOnChildrenLoadedWithOptions = false;
mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoadedWithOptions);
+ assertTrue(mOnChildrenLoadedWithOptions);
}
}
public void testDelayedNotifyChildrenChanged() throws Exception {
synchronized (mWaitLock) {
- mSubscriptionCallback.reset();
+ mOnChildrenLoaded = false;
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED,
mSubscriptionCallback);
mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mSubscriptionCallback.mOnChildrenLoaded);
+ assertFalse(mOnChildrenLoaded);
mMediaBrowserService.sendDelayedNotifyChildrenChanged();
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+ assertTrue(mOnChildrenLoaded);
- mSubscriptionCallback.reset();
+ mOnChildrenLoaded = false;
mMediaBrowserService.notifyChildrenChanged(
StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED);
mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mSubscriptionCallback.mOnChildrenLoaded);
+ assertFalse(mOnChildrenLoaded);
mMediaBrowserService.sendDelayedNotifyChildrenChanged();
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+ assertTrue(mOnChildrenLoaded);
}
}
public void testDelayedItem() throws Exception {
synchronized (mWaitLock) {
- mItemCallback.reset();
- mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED, mItemCallback);
+ mOnItemLoaded = false;
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED,
+ mItemCallback);
mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mItemCallback.mOnItemLoaded);
+ assertFalse(mOnItemLoaded);
- mItemCallback.reset();
mMediaBrowserService.sendDelayedItemLoaded();
mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mItemCallback.mOnItemLoaded);
+ assertTrue(mOnItemLoaded);
}
}
@@ -155,60 +203,6 @@
assertEquals(val, browserRoot.getExtras().getString(key));
}
- public void testSearch() throws Exception {
- final String key = "test-key";
- final String val = "test-val";
-
- final MediaBrowser.SearchCallback searchCallback =
- (MediaBrowser.SearchCallback) mSearchCallback;
- final MediaBrowserService mediaBrowserService = (MediaBrowserService) mMediaBrowserService;
-
- synchronized (mWaitLock) {
- mSearchCallback.reset();
- mMediaBrowser.search(StubMediaBrowserService.SEARCH_QUERY_FOR_NO_RESULT, null,
- mSearchCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(mSearchCallback.mOnSearchResult);
- assertTrue(mSearchCallback.mSearchResults != null
- && mSearchCallback.mSearchResults.size() == 0);
- assertEquals(null, mSearchCallback.mSearchExtras);
- // just call the callback once directly so it's marked as tested
- mediaBrowserService.onSearch(
- StubMediaBrowserService.SEARCH_QUERY_FOR_NO_RESULT, null, null);
- searchCallback.onSearchResult(StubMediaBrowserService.SEARCH_QUERY_FOR_NO_RESULT,
- mSearchCallback.mSearchExtras, mSearchCallback.mSearchResults);
-
- mSearchCallback.reset();
- mMediaBrowser.search(StubMediaBrowserService.SEARCH_QUERY_FOR_ERROR, null,
- mSearchCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(mSearchCallback.mOnSearchResult);
- assertNull(mSearchCallback.mSearchResults);
- assertEquals(null, mSearchCallback.mSearchExtras);
- // just call the callback once directly so it's marked as tested
- mediaBrowserService.onSearch(
- StubMediaBrowserService.SEARCH_QUERY_FOR_ERROR, null, null);
- searchCallback.onError(StubMediaBrowserService.SEARCH_QUERY_FOR_ERROR, null);
-
- mSearchCallback.reset();
- Bundle extras = new Bundle();
- extras.putString(key, val);
- mMediaBrowser.search(StubMediaBrowserService.SEARCH_QUERY, extras, mSearchCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(mSearchCallback.mOnSearchResult);
- assertNotNull(mSearchCallback.mSearchResults);
- for (MediaItem item : mSearchCallback.mSearchResults) {
- assertTrue(item.getMediaId().contains(StubMediaBrowserService.SEARCH_QUERY));
- }
- assertNotNull(mSearchCallback.mSearchExtras);
- assertEquals(val, mSearchCallback.mSearchExtras.getString(key));
- // just call the callback once directly so it's marked as tested
- mediaBrowserService.onSearch(StubMediaBrowserService.SEARCH_QUERY, extras, null);
- searchCallback.onSearchResult(StubMediaBrowserService.SEARCH_QUERY,
- mSearchCallback.mSearchExtras, mSearchCallback.mSearchResults);
- }
- }
-
private void assertRootHints(MediaItem item) {
Bundle rootHints = item.getDescription().getExtras();
assertNotNull(rootHints);
@@ -219,100 +213,4 @@
assertEquals(mRootHints.getBoolean(BrowserRoot.EXTRA_SUGGESTED),
rootHints.getBoolean(BrowserRoot.EXTRA_SUGGESTED));
}
-
- private class ConnectionCallback extends MediaBrowser.ConnectionCallback {
- @Override
- public void onConnected() {
- synchronized (mWaitLock) {
- mMediaBrowserService = StubMediaBrowserService.sInstance;
- mWaitLock.notify();
- }
- }
- }
-
- private class SubscriptionCallback extends MediaBrowser.SubscriptionCallback {
- boolean mOnChildrenLoaded;
- boolean mOnChildrenLoadedWithOptions;
-
- @Override
- public void onChildrenLoaded(String parentId, List<MediaItem> children) {
- synchronized (mWaitLock) {
- mOnChildrenLoaded = true;
- if (children != null) {
- for (MediaItem item : children) {
- assertRootHints(item);
- }
- }
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onChildrenLoaded(String parentId, List<MediaItem> children,
- Bundle options) {
- synchronized (mWaitLock) {
- mOnChildrenLoadedWithOptions = true;
- if (children != null) {
- for (MediaItem item : children) {
- assertRootHints(item);
- }
- }
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnChildrenLoaded = false;
- mOnChildrenLoadedWithOptions = false;
- }
- }
-
- private class ItemCallback extends MediaBrowser.ItemCallback {
- boolean mOnItemLoaded;
-
- @Override
- public void onItemLoaded(MediaItem item) {
- synchronized (mWaitLock) {
- mOnItemLoaded = true;
- assertRootHints(item);
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnItemLoaded = false;
- }
- }
-
- private class SearchCallback extends MediaBrowser.SearchCallback {
- boolean mOnSearchResult;
- Bundle mSearchExtras;
- List<MediaItem> mSearchResults;
-
- @Override
- public void onSearchResult(String query, Bundle extras, List<MediaItem> items) {
- synchronized (mWaitLock) {
- mOnSearchResult = true;
- mSearchResults = items;
- mSearchExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onError(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnSearchResult = true;
- mSearchResults = null;
- mSearchExtras = extras;
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnSearchResult = false;
- mSearchExtras = null;
- mSearchResults = null;
- }
- }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCasTest.java b/tests/tests/media/src/android/media/cts/MediaCasTest.java
index d2ae849..a3cdefc 100644
--- a/tests/tests/media/src/android/media/cts/MediaCasTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCasTest.java
@@ -18,6 +18,7 @@
import android.media.MediaCas;
import android.media.MediaCas.PluginDescriptor;
+import android.media.MediaCas.Session;
import android.media.MediaCasException;
import android.media.MediaCasException.UnsupportedCasException;
import android.media.MediaCasStateException;
@@ -181,10 +182,10 @@
}, null);
} finally {
if (mediaCas != null) {
- mediaCas.release();
+ mediaCas.close();
}
if (descrambler != null) {
- descrambler.release();
+ descrambler.close();
}
}
}
@@ -213,10 +214,10 @@
}
} finally {
if (unsupportedCAS != null) {
- unsupportedCAS.release();
+ unsupportedCAS.close();
}
if (unsupportedDescrambler != null) {
- unsupportedDescrambler.release();
+ unsupportedDescrambler.close();
}
}
}
@@ -247,24 +248,22 @@
byte[] pvtData = new byte[256];
mediaCas.setPrivateData(pvtData);
- int program_number = 72849;
- int elementary_PID = 256;
- byte[] sessionId = mediaCas.openSession(72849);
- if (sessionId == null || sessionId.length == 0) {
+ Session session = mediaCas.openSession();
+ if (session == null) {
fail("Can't open session for program");
}
- mediaCas.setSessionPrivateData(sessionId, pvtData);
+ session.setPrivateData(pvtData);
- byte[] streamSessionId = mediaCas.openSession(72849, 256);
- if (streamSessionId == null || streamSessionId.length == 0) {
+ Session streamSession = mediaCas.openSession();
+ if (streamSession == null) {
fail("Can't open session for stream");
}
- mediaCas.setSessionPrivateData(streamSessionId, pvtData);
+ streamSession.setPrivateData(pvtData);
- descrambler.setMediaCasSession(sessionId);
+ descrambler.setMediaCasSession(session);
- descrambler.setMediaCasSession(streamSessionId);
+ descrambler.setMediaCasSession(streamSession);
mediaCas.refreshEntitlements(3, null);
@@ -291,8 +290,8 @@
mediaCas.processEmm(emmData);
byte[] ecmData = loadByteArrayFromString(sEcmBufferStr);
- mediaCas.processEcm(sessionId, ecmData);
- mediaCas.processEcm(streamSessionId, ecmData);
+ session.processEcm(ecmData);
+ streamSession.processEcm(ecmData);
ByteBuffer outputBuf = descrambleTestInputBuffer(descrambler);
ByteBuffer expectedOutputBuf = ByteBuffer.wrap(
@@ -300,14 +299,14 @@
assertTrue("Incorrect decryption result",
expectedOutputBuf.compareTo(outputBuf) == 0);
- mediaCas.closeSession(sessionId);
- mediaCas.closeSession(streamSessionId);
+ session.close();
+ streamSession.close();
} finally {
if (mediaCas != null) {
- mediaCas.release();
+ mediaCas.close();
}
if (descrambler != null) {
- descrambler.release();
+ descrambler.close();
}
}
}
@@ -324,28 +323,28 @@
descrambler = new MediaDescrambler(sClearKeySystemId);
mediaCas.provision(sProvisionStr);
- byte[] sessionId = mediaCas.openSession(72849);
- if (sessionId == null || sessionId.length == 0) {
+ Session session = mediaCas.openSession();
+ if (session == null) {
fail("Can't open session for program");
}
- byte[] streamSessionId = mediaCas.openSession(72849, 256);
- if (streamSessionId == null || streamSessionId.length == 0) {
+ Session streamSession = mediaCas.openSession();
+ if (streamSession == null) {
fail("Can't open session for stream");
}
- mediaCas.release();
+ mediaCas.close();
mediaCas = null;
try {
- descrambler.setMediaCasSession(sessionId);
+ descrambler.setMediaCasSession(session);
fail("Program session not closed after MediaCas is released");
} catch (MediaCasStateException e) {
Log.d(TAG, "setMediaCasSession throws "
+ e.getDiagnosticInfo() + " (as expected)");
}
try {
- descrambler.setMediaCasSession(streamSessionId);
+ descrambler.setMediaCasSession(streamSession);
fail("Stream session not closed after MediaCas is released");
} catch (MediaCasStateException e) {
Log.d(TAG, "setMediaCasSession throws "
@@ -353,10 +352,10 @@
}
} finally {
if (mediaCas != null) {
- mediaCas.release();
+ mediaCas.close();
}
if (descrambler != null) {
- descrambler.release();
+ descrambler.close();
}
}
}
@@ -393,26 +392,31 @@
Log.d(TAG, "processEmm throws ArrayIndexOutOfBoundsException (as expected)");
}
- byte[] invalidSessionId = new byte[] {};
+ // open a session, then close it so that it should become invalid
+ Session invalidSession = mediaCas.openSession();
+ if (invalidSession == null) {
+ fail("Can't open session for program");
+ }
+ invalidSession.close();
byte[] ecmData = loadByteArrayFromString(sEcmBufferStr);
// processEcm should fail with an invalid session id
try {
- mediaCas.processEcm(invalidSessionId, ecmData);
+ invalidSession.processEcm(ecmData);
fail("processEcm shouldn't succeed with invalid session id");
} catch (MediaCasStateException e) {
Log.d(TAG, "processEcm throws " + e.getDiagnosticInfo() + " (as expected)");
}
- byte[] sessionId = mediaCas.openSession(72849);
- if (sessionId == null || sessionId.length == 0) {
+ Session session = mediaCas.openSession();
+ if (session == null) {
fail("Can't open session for program");
}
// processEcm should fail without provisioning
try {
- mediaCas.processEcm(sessionId, ecmData);
+ session.processEcm(ecmData);
fail("processEcm shouldn't succeed without provisioning");
} catch (MediaCasException.NotProvisionedException e) {
Log.d(TAG, "processEcm throws NotProvisionedException (as expected)");
@@ -423,7 +427,7 @@
// processEcm should fail with ecm buffer that's too short
try {
- mediaCas.processEcm(sessionId, ecmData, 0, 8);
+ session.processEcm(ecmData, 0, 8);
fail("processEcm shouldn't succeed with truncated ecm");
} catch (IllegalArgumentException e) {
Log.d(TAG, "processEcm throws " + e.toString() + " (as expected)");
@@ -432,7 +436,7 @@
// processEcm should fail with ecm with bad descriptor count
try {
ecmData[17] = 3; // change the descriptor count field to 3 (invalid)
- mediaCas.processEcm(sessionId, ecmData);
+ session.processEcm(ecmData);
fail("processEcm shouldn't succeed with altered descriptor count");
} catch (MediaCasStateException e) {
Log.d(TAG, "processEcm throws " + e.getDiagnosticInfo() + " (as expected)");
@@ -444,7 +448,7 @@
// setMediaCasSession should fail with an invalid session id
try {
- descrambler.setMediaCasSession(invalidSessionId);
+ descrambler.setMediaCasSession(invalidSession);
fail("setMediaCasSession shouldn't succeed with invalid session id");
} catch (MediaCasStateException e) {
Log.d(TAG, "setMediaCasSession throws "
@@ -460,7 +464,7 @@
}
// Now set a valid session, should still fail because no valid ecm is processed
- descrambler.setMediaCasSession(sessionId);
+ descrambler.setMediaCasSession(session);
try {
ByteBuffer outputBuf = descrambleTestInputBuffer(descrambler);
fail("descramble should fail without valid ecm");
@@ -469,10 +473,10 @@
}
} finally {
if (mediaCas != null) {
- mediaCas.release();
+ mediaCas.close();
}
if (descrambler != null) {
- descrambler.release();
+ descrambler.close();
}
}
}
@@ -537,7 +541,7 @@
ByteBuffer inputBuf = ByteBuffer.wrap(
loadByteArrayFromString(sInputBufferStr));
ByteBuffer outputBuf = ByteBuffer.allocate(inputBuf.capacity());
- descrambler.descramble(inputBuf, 0, outputBuf, 0, cryptoInfo);
+ descrambler.descramble(inputBuf, outputBuf, cryptoInfo);
return outputBuf;
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 253a5ab..99f2790 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -230,8 +230,6 @@
private void prepareVideo() throws IOException {
boolean hasVideo = false;
- android.media.DrmInitData drmInitData = mVideoExtractor.getDrmInitData();
-
for (int i = mVideoExtractor.getTrackCount(); i-- > 0;) {
MediaFormat format = mVideoExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
@@ -244,11 +242,10 @@
Log.d(TAG, "video track #" + i + " " + format + " " + mime +
" Width:" + mMediaFormatWidth + ", Height:" + mMediaFormatHeight);
- if (mScrambled && drmInitData != null && mime.startsWith("video/")) {
- android.media.DrmInitData.SchemeInitData schemeInitData =
- drmInitData.get(new UUID(0, i));
- if (schemeInitData != null) {
- mDescrambler.setMediaCasSession(schemeInitData.data);
+ if (mScrambled && mime.startsWith("video/")) {
+ MediaExtractor.CasInfo casInfo = mVideoExtractor.getCasInfo(i);
+ if (casInfo != null && casInfo.getSession() != null) {
+ mDescrambler.setMediaCasSession(casInfo.getSession());
}
}
@@ -291,23 +288,18 @@
private void initCasAndDescrambler(MediaExtractor extractor) throws MediaCasException {
int trackCount = extractor.getTrackCount();
- android.media.DrmInitData drmInitData = extractor.getDrmInitData();
for (int trackId = 0; trackId < trackCount; trackId++) {
android.media.MediaFormat format = extractor.getTrackFormat(trackId);
String mime = format.getString(android.media.MediaFormat.KEY_MIME);
Log.d(TAG, "track "+ trackId + ": " + mime);
if ("video/scrambled".equals(mime) || "audio/scrambled".equals(mime)) {
- if (drmInitData == null) {
- throw new IllegalArgumentException("found scrambled track without drmInitData!");
+ MediaExtractor.CasInfo casInfo = extractor.getCasInfo(trackId);
+ if (casInfo != null) {
+ mMediaCas = new MediaCas(casInfo.getSystemId());
+ mDescrambler = new MediaDescrambler(casInfo.getSystemId());
+ mMediaCas.provision(sProvisionStr);
+ extractor.setMediaCas(mMediaCas);
}
- android.media.DrmInitData.SchemeInitData schemeInitData =
- drmInitData.get(new UUID(0, trackId));
- int CA_system_id = (schemeInitData.data[0] & 0xff)
- | ((schemeInitData.data[1] & 0xff) << 8);
- mMediaCas = new MediaCas(CA_system_id);
- mDescrambler = new MediaDescrambler(CA_system_id);
- mMediaCas.provision(sProvisionStr);
- extractor.setMediaCas(mMediaCas);
}
}
}
@@ -550,12 +542,12 @@
}
if (mMediaCas != null) {
- mMediaCas.release();
+ mMediaCas.close();
mMediaCas = null;
}
if (mDescrambler != null) {
- mDescrambler.release();
+ mDescrambler.close();
mDescrambler = null;
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 9b941a2..56cbc93 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -32,10 +32,10 @@
import android.media.MediaFormat;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.CodecProfileLevel;
-import android.media.MediaMetricsSet;
import android.opengl.GLES20;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.PersistableBundle;
import android.support.test.filters.SmallTest;
import android.platform.test.annotations.RequiresDevice;
import android.test.AndroidTestCase;
@@ -919,17 +919,17 @@
// good
}
- MediaMetricsSet metricsSet = encoder.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = encoder.getMetrics();
+ if (metrics == null) {
fail("getMetrics() returns null");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("getMetrics() returns empty results");
}
- int encoding = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+ int encoding = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
if (encoding != 1) {
fail("getMetrics() returns bad encoder value " + encoding);
}
- String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+ String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
if (theCodec == null) {
fail("getMetrics() returns null codec value ");
}
@@ -989,17 +989,17 @@
// good
}
- MediaMetricsSet metricsSet = encoder.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = encoder.getMetrics();
+ if (metrics == null) {
fail("getMetrics() returns null");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("getMetrics() returns empty results");
}
- int encoding = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+ int encoding = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
if (encoding != 1) {
fail("getMetrics() returns bad encoder value " + encoding);
}
- String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+ String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
if (theCodec == null) {
fail("getMetrics() returns null codec value ");
}
@@ -1050,17 +1050,17 @@
throw new RuntimeException("decoder does not generate non-empty output.");
}
- MediaMetricsSet metricsSet = mediaCodec.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = mediaCodec.getMetrics();
+ if (metrics == null) {
fail("getMetrics() returns null");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("getMetrics() returns empty results");
}
- int encoder = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+ int encoder = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
if (encoder != 0) {
fail("getMetrics() returns bad encoder value " + encoder);
}
- String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+ String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
if (theCodec == null) {
fail("getMetrics() returns null codec value ");
}
@@ -1071,17 +1071,17 @@
mediaCodec.flush();
completed.set(runDecodeTillFirstOutput(mediaCodec, mediaExtractor));
- metricsSet = mediaCodec.getMetrics();
- if (metricsSet == null) {
+ metrics = mediaCodec.getMetrics();
+ if (metrics == null) {
fail("getMetrics() returns null");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("getMetrics() returns empty results");
}
- int encoding = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+ int encoding = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
if (encoding != 0) {
fail("getMetrics() returns bad encoder value " + encoding);
}
- String theCodec2 = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+ String theCodec2 = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
if (theCodec2 == null) {
fail("getMetrics() returns null codec value ");
}
@@ -1092,17 +1092,17 @@
if (mediaCodec != null) {
mediaCodec.stop();
- MediaMetricsSet metricsSet = mediaCodec.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = mediaCodec.getMetrics();
+ if (metrics == null) {
fail("getMetrics() returns null");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("getMetrics() returns empty results");
}
- int encoder = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+ int encoder = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
if (encoder != 0) {
fail("getMetrics() returns bad encoder value " + encoder);
}
- String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+ String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
if (theCodec == null) {
fail("getMetrics() returns null codec value ");
}
@@ -1166,14 +1166,14 @@
}
assertTrue("Wrong output buffer index", outputBufferIndex >= 0);
- MediaMetricsSet metricsSet = mediaCodec.getMetrics();
- Log.d(TAG, "getMetrics after first buffer metricsSet says: " + metricsSet);
+ PersistableBundle metrics = mediaCodec.getMetrics();
+ Log.d(TAG, "getMetrics after first buffer metrics says: " + metrics);
- int encoder = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+ int encoder = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
if (encoder != 0) {
fail("getMetrics() returns bad encoder value " + encoder);
}
- String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+ String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
if (theCodec == null) {
fail("getMetrics() returns null codec value ");
}
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index 9aaf1aa..17588ee 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -19,11 +19,8 @@
import android.media.AudioManager;
import android.media.Rating;
import android.media.VolumeProvider;
-import android.media.MediaDescription;
import android.media.session.MediaController;
import android.media.session.MediaSession;
-import android.media.session.MediaSession.QueueItem;
-import android.media.session.PlaybackState;
import android.media.session.PlaybackState.CustomAction;
import android.net.Uri;
import android.os.Bundle;
@@ -53,7 +50,6 @@
super.setUp();
mSession = new MediaSession(getContext(), SESSION_TAG);
mSession.setCallback(mCallback, mHandler);
- mSession.setFlags(MediaSession.FLAG_HANDLES_QUEUE_COMMANDS);
mController = mSession.getController();
}
@@ -88,53 +84,6 @@
}
}
- public void testAddRemoveQueueItems() throws Exception {
- final String mediaId = "media_id";
- final String mediaTitle = "media_title";
- MediaDescription itemDescription = new MediaDescription.Builder()
- .setMediaId(mediaId).setTitle(mediaTitle).build();
- final MediaSession.Callback callback = (MediaSession.Callback) mCallback;
-
- synchronized (mWaitLock) {
- mCallback.reset();
- mController.addQueueItem(itemDescription);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemCalled);
- assertEquals(-1, mCallback.mQueueIndex);
- assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
- // just call the callback once directly so it's marked as tested
- callback.onAddQueueItem(mCallback.mQueueDescription);
-
- mCallback.reset();
- mController.addQueueItem(itemDescription, 0);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemAtCalled);
- assertEquals(0, mCallback.mQueueIndex);
- assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
- // just call the callback once directly so it's marked as tested
- callback.onAddQueueItem(mCallback.mQueueDescription, mCallback.mQueueIndex);
-
- mCallback.reset();
- mController.removeQueueItemAt(0);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRemoveQueueItemAtCalled);
- assertEquals(0, mCallback.mQueueIndex);
- // just call the callback once directly so it's marked as tested
- callback.onRemoveQueueItemAt(mCallback.mQueueIndex);
-
- mCallback.reset();
- mController.removeQueueItem(itemDescription);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRemoveQueueItemCalled);
- assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
- // just call the callback once directly so it's marked as tested
- callback.onRemoveQueueItem(mCallback.mQueueDescription);
- }
- }
-
public void testVolumeControl() throws Exception {
VolumeProvider vp = new VolumeProvider(VolumeProvider.VOLUME_CONTROL_ABSOLUTE, 11, 5) {
@Override
@@ -346,26 +295,6 @@
assertTrue(mCallback.mOnPrepareFromUriCalled);
assertEquals(uri, mCallback.mUri);
assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
- // just call the callback once directly so it's marked as tested
- callback.onPrepareFromUri(mCallback.mUri, mCallback.mExtras);
-
- mCallback.reset();
- final int repeatMode = PlaybackState.REPEAT_MODE_ALL;
- controls.setRepeatMode(repeatMode);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRepeatModeCalled);
- assertEquals(repeatMode, mCallback.mRepeatMode);
- // just call the callback once directly so it's marked as tested
- callback.onSetRepeatMode(mCallback.mRepeatMode);
-
- mCallback.reset();
- final boolean shuffleModeEnabled = true;
- controls.setShuffleModeEnabled(shuffleModeEnabled);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetShuffleModeEnabledCalled);
- assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
- // just call the callback once directly so it's marked as tested
- callback.onSetShuffleModeEnabled(mCallback.mShuffleModeEnabled);
}
}
@@ -389,8 +318,6 @@
private class MediaSessionCallback extends MediaSession.Callback {
private long mSeekPosition;
private long mQueueItemId;
- private int mQueueIndex;
- private MediaDescription mQueueDescription;
private Rating mRating;
private String mMediaId;
private String mQuery;
@@ -399,8 +326,6 @@
private String mCommand;
private Bundle mExtras;
private ResultReceiver mCommandCallback;
- private int mRepeatMode;
- private boolean mShuffleModeEnabled;
private boolean mOnPlayCalled;
private boolean mOnPauseCalled;
@@ -421,18 +346,10 @@
private boolean mOnPrepareFromMediaIdCalled;
private boolean mOnPrepareFromSearchCalled;
private boolean mOnPrepareFromUriCalled;
- private boolean mOnSetRepeatModeCalled;
- private boolean mOnSetShuffleModeEnabledCalled;
- private boolean mOnAddQueueItemCalled;
- private boolean mOnAddQueueItemAtCalled;
- private boolean mOnRemoveQueueItemCalled;
- private boolean mOnRemoveQueueItemAtCalled;
public void reset() {
mSeekPosition = -1;
mQueueItemId = -1;
- mQueueIndex = -1;
- mQueueDescription = null;
mRating = null;
mMediaId = null;
mQuery = null;
@@ -441,8 +358,6 @@
mExtras = null;
mCommand = null;
mCommandCallback = null;
- mShuffleModeEnabled = false;
- mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
mOnPlayCalled = false;
mOnPauseCalled = false;
@@ -463,12 +378,6 @@
mOnPrepareFromMediaIdCalled = false;
mOnPrepareFromSearchCalled = false;
mOnPrepareFromUriCalled = false;
- mOnSetRepeatModeCalled = false;
- mOnSetShuffleModeEnabledCalled = false;
- mOnAddQueueItemCalled = false;
- mOnAddQueueItemAtCalled = false;
- mOnRemoveQueueItemCalled = false;
- mOnRemoveQueueItemAtCalled = false;
}
@Override
@@ -642,60 +551,5 @@
mWaitLock.notify();
}
}
-
- @Override
- public void onSetRepeatMode(int repeatMode) {
- synchronized (mWaitLock) {
- mOnSetRepeatModeCalled = true;
- mRepeatMode = repeatMode;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSetShuffleModeEnabled(boolean enabled) {
- synchronized (mWaitLock) {
- mOnSetShuffleModeEnabledCalled = true;
- mShuffleModeEnabled = enabled;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onAddQueueItem(MediaDescription description) {
- synchronized (mWaitLock) {
- mOnAddQueueItemCalled = true;
- mQueueDescription = description;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onAddQueueItem(MediaDescription description, int index) {
- synchronized (mWaitLock) {
- mOnAddQueueItemAtCalled = true;
- mQueueIndex = index;
- mQueueDescription = description;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onRemoveQueueItem(MediaDescription description) {
- synchronized (mWaitLock) {
- mOnRemoveQueueItemCalled = true;
- mQueueDescription = description;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onRemoveQueueItemAt(int index) {
- synchronized (mWaitLock) {
- mOnRemoveQueueItemAtCalled = true;
- mQueueIndex = index;
- mWaitLock.notify();
- }
- }
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 7248c7d..b6f34f4 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -17,12 +17,12 @@
package android.media.cts;
import android.media.cts.R;
-import android.media.MediaMetricsSet;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.media.MediaDataSource;
import android.media.MediaExtractor;
+import android.os.PersistableBundle;
import android.test.AndroidTestCase;
import java.io.IOException;
@@ -110,12 +110,12 @@
}
// verify some getMetrics() behaviors while we're here.
- MediaMetricsSet metricsSet = mExtractor.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = mExtractor.getMetrics();
+ if (metrics == null) {
fail("getMetrics() returns no data");
} else {
// ensure existence of some known fields
- int tracks = metricsSet.getInt(MediaMetricsSet.MediaExtractor.KEY_TRACKS, -1);
+ int tracks = metrics.getInt(MediaExtractor.MetricsConstants.TRACKS, -1);
if (tracks != trackCount) {
fail("getMetrics() trackCount expect " + trackCount + " got " + tracks);
}
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index 2431bf2..82b992d 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -20,8 +20,8 @@
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.media.MediaPlayer;
-import android.media.MediaMetricsSet;
import android.net.Uri;
+import android.os.PersistableBundle;
import android.test.ActivityInstrumentationTestCase2;
import com.android.compatibility.common.util.MediaUtils;
@@ -324,15 +324,15 @@
}
// validate a few MediaMetrics.
- MediaMetricsSet metricsSet = mMediaPlayer.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = mMediaPlayer.getMetrics();
+ if (metrics == null) {
fail("MediaPlayer.getMetrics() returned null metrics");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("MediaPlayer.getMetrics() returned empty metrics");
} else {
- int size = metricsSet.size();
- Set<String> keys = metricsSet.keySet();
+ int size = metrics.size();
+ Set<String> keys = metrics.keySet();
if (keys == null) {
fail("MediaMetricsSet returned no keys");
@@ -341,22 +341,22 @@
}
// we played something; so one of these should be non-null
- String vmime = metricsSet.getString(MediaMetricsSet.MediaPlayer.KEY_MIME_VIDEO, null);
- String amime = metricsSet.getString(MediaMetricsSet.MediaPlayer.KEY_MIME_AUDIO, null);
+ String vmime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_VIDEO, null);
+ String amime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_AUDIO, null);
if (vmime == null && amime == null) {
fail("getMetrics() returned neither video nor audio mime value");
}
- long duration = metricsSet.getLong(MediaMetricsSet.MediaPlayer.KEY_DURATION, -2);
+ long duration = metrics.getLong(MediaPlayer.MetricsConstants.DURATION, -2);
if (duration == -2) {
fail("getMetrics() didn't return a duration");
}
- long playing = metricsSet.getLong(MediaMetricsSet.MediaPlayer.KEY_PLAYING, -2);
+ long playing = metrics.getLong(MediaPlayer.MetricsConstants.PLAYING, -2);
if (playing == -2) {
fail("getMetrics() didn't return a playing time");
}
- if (!keys.contains(MediaMetricsSet.MediaPlayer.KEY_PLAYING)) {
- fail("MediaMetricsSet.keys() missing: " + MediaMetricsSet.MediaPlayer.KEY_PLAYING);
+ if (!keys.contains(MediaPlayer.MetricsConstants.PLAYING)) {
+ fail("MediaMetricsSet.keys() missing: " + MediaPlayer.MetricsConstants.PLAYING);
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index fbf51ca..d3c392c 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -30,10 +30,10 @@
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OnInfoListener;
import android.media.MediaMetadataRetriever;
-import android.media.MediaMetricsSet;
import android.os.ConditionVariable;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.support.test.filters.SmallTest;
import android.platform.test.annotations.RequiresDevice;
import android.test.ActivityInstrumentationTestCase2;
@@ -230,14 +230,14 @@
// verify some getMetrics() behaviors while we're here.
- MediaMetricsSet metricsSet = mMediaRecorder.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = mMediaRecorder.getMetrics();
+ if (metrics == null) {
fail("MediaRecorder.getMetrics() returned null metrics");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("MediaRecorder.getMetrics() returned empty metrics");
} else {
- int size = metricsSet.size();
- Set<String> keys = metricsSet.keySet();
+ int size = metrics.size();
+ Set<String> keys = metrics.keySet();
if (size == 0) {
fail("MediaRecorder.getMetrics().size() reports empty record");
@@ -250,14 +250,14 @@
}
// ensure existence of some known fields
- int videoBitRate = metricsSet.getInt(MediaMetricsSet.MediaRecorder.KEY_VIDEO_BITRATE, -1);
+ int videoBitRate = metrics.getInt(MediaRecorder.MetricsConstants.VIDEO_BITRATE, -1);
if (videoBitRate != VIDEO_BIT_RATE_IN_BPS) {
fail("getMetrics() videoEncodeBitrate set " +
VIDEO_BIT_RATE_IN_BPS + " got " + videoBitRate);
}
// careful when comparing floating point numbers
- double captureFrameRate = metricsSet.getDouble(MediaMetricsSet.MediaRecorder.KEY_CAPTURE_FPS, -1);
+ double captureFrameRate = metrics.getDouble(MediaRecorder.MetricsConstants.CAPTURE_FPS, -1);
if (captureFrameRate < 0) {
fail("getMetrics() capture framerate reports " + captureFrameRate);
}
@@ -304,14 +304,14 @@
Thread.sleep(RECORD_TIME_MS);
// verify some getMetrics() behaviors while we're here.
- MediaMetricsSet metricsSet = mMediaRecorder.getMetrics();
- if (metricsSet == null) {
+ PersistableBundle metrics = mMediaRecorder.getMetrics();
+ if (metrics == null) {
fail("MediaRecorder.getMetrics() returned null metrics");
- } else if (metricsSet.isEmpty()) {
+ } else if (metrics.isEmpty()) {
fail("MediaRecorder.getMetrics() returned empty metrics");
} else {
- int size = metricsSet.size();
- Set<String> keys = metricsSet.keySet();
+ int size = metrics.size();
+ Set<String> keys = metrics.keySet();
if (size == 0) {
fail("MediaRecorder.getMetrics().size() reports empty record");
@@ -324,14 +324,14 @@
}
// ensure existence of some known fields
- int videoBitRate = metricsSet.getInt(MediaMetricsSet.MediaRecorder.KEY_VIDEO_BITRATE, -1);
+ int videoBitRate = metrics.getInt(MediaRecorder.MetricsConstants.VIDEO_BITRATE, -1);
if (videoBitRate != VIDEO_BIT_RATE_IN_BPS) {
fail("getMetrics() videoEncodeBitrate set " +
VIDEO_BIT_RATE_IN_BPS + " got " + videoBitRate);
}
// careful when comparing floating point numbers
- double captureFrameRate = metricsSet.getDouble(MediaMetricsSet.MediaRecorder.KEY_CAPTURE_FPS, -1);
+ double captureFrameRate = metrics.getDouble(MediaRecorder.MetricsConstants.CAPTURE_FPS, -1);
if (captureFrameRate < 0) {
fail("getMetrics() capture framerate reports " + captureFrameRate);
}
@@ -520,6 +520,19 @@
fos.close();
}
+ public void testSetOutputFile() throws Exception {
+ if (!hasCamera()) {
+ return;
+ }
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
+ mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
+ mMediaRecorder.setOutputFile(mOutFile);
+ long maxFileSize = MAX_FILE_SIZE * 10;
+ recordMedia(maxFileSize, mOutFile);
+ }
+
public void testRecordingAudioInRawFormats() throws Exception {
int testsRun = 0;
if (hasAmrNb()) {
@@ -771,7 +784,8 @@
} else if (mFileIndex < 6) {
try {
String path = OUTPUT_PATH + mFileIndex;
- mMediaRecorder.setNextOutputFile(path);
+ File nextFile = new File(path);
+ mMediaRecorder.setNextOutputFile(nextFile);
recordFileList.add(path);
mFileIndex++;
} catch (IOException e) {
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index 50b3033..07f63da 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -149,6 +149,9 @@
session.setPlaybackState(state);
session.setActive(true);
+ // A media playback is also needed to receive media key events.
+ Utils.assertMediaPlaybackStarted(getInstrumentation().getTargetContext());
+
// Ensure that the listener is called for media key event,
// and any other media sessions don't get the key.
MediaKeyListener listener = new MediaKeyListener(2, true, handler);
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index b84bf1c..5f13a2e 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
@@ -222,28 +222,6 @@
mSession.setSessionActivity(pi);
assertEquals(pi, controller.getSessionActivity());
- // test setRepeatMode
- mCallback.resetLocked();
- final int repeatMode = PlaybackState.REPEAT_MODE_ALL;
- mSession.setRepeatMode(repeatMode);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRepeatModeChangedCalled);
- assertEquals(repeatMode, mCallback.mRepeatMode);
- assertEquals(repeatMode, controller.getRepeatMode());
- // just call the callback once directly so it's marked as tested
- callback.onRepeatModeChanged(mCallback.mRepeatMode);
-
- // test setShuffleModeEnabled
- mCallback.resetLocked();
- final boolean shuffleModeEnabled = true;
- mSession.setShuffleModeEnabled(shuffleModeEnabled);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnShuffleModeChangedCalled);
- assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
- assertEquals(shuffleModeEnabled, controller.isShuffleModeEnabled());
- // just call the callback once directly so it's marked as tested
- callback.onShuffleModeChanged(mCallback.mShuffleModeEnabled);
-
// test setActivity
mSession.setActive(true);
assertTrue(mSession.isActive());
@@ -354,6 +332,9 @@
.setState(PlaybackState.STATE_PLAYING, 0L, 0.0f).build();
mSession.setPlaybackState(defaultState);
+ // A media playback is also needed to receive media key events.
+ Utils.assertMediaPlaybackStarted(getContext());
+
synchronized (mWaitLock) {
sessionCallback.reset();
simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY);
@@ -474,8 +455,6 @@
private volatile boolean mOnAudioInfoChangedCalled;
private volatile boolean mOnSessionDestroyedCalled;
private volatile boolean mOnSessionEventCalled;
- private volatile boolean mOnRepeatModeChangedCalled;
- private volatile boolean mOnShuffleModeChangedCalled;
private volatile PlaybackState mPlaybackState;
private volatile MediaMetadata mMediaMetadata;
@@ -484,8 +463,6 @@
private volatile String mEvent;
private volatile Bundle mExtras;
private volatile MediaController.PlaybackInfo mPlaybackInfo;
- private volatile int mRepeatMode;
- private volatile boolean mShuffleModeEnabled;
public void resetLocked() {
mOnPlaybackStateChangedCalled = false;
@@ -496,8 +473,6 @@
mOnAudioInfoChangedCalled = false;
mOnSessionDestroyedCalled = false;
mOnSessionEventCalled = false;
- mOnRepeatModeChangedCalled = false;
- mOnShuffleModeChangedCalled = false;
mPlaybackState = null;
mMediaMetadata = null;
@@ -505,8 +480,6 @@
mTitle = null;
mExtras = null;
mPlaybackInfo = null;
- mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
- mShuffleModeEnabled = false;
}
@Override
@@ -580,24 +553,6 @@
mWaitLock.notify();
}
}
-
- @Override
- public void onRepeatModeChanged(int repeatMode) {
- synchronized (mWaitLock) {
- mOnRepeatModeChangedCalled = true;
- mRepeatMode = repeatMode;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onShuffleModeChanged(boolean enabled) {
- synchronized (mWaitLock) {
- mOnShuffleModeChangedCalled = true;
- mShuffleModeEnabled = enabled;
- mWaitLock.notify();
- }
- }
}
private class MediaSessionCallback extends MediaSession.Callback {
diff --git a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
index 96b33da..3dff5bf 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
@@ -99,12 +99,19 @@
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
}
+ private boolean isTV() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
+ }
+
public void testConstructors() {
new RingtoneManager(mActivity);
new RingtoneManager(mContext);
}
public void testAccessMethods() {
+ if (isTV()) {
+ return;
+ }
if (!hasAudioOutput()) {
Log.i(TAG, "Skipping testAccessMethods(): device doesn't have audio output.");
return;
@@ -145,6 +152,9 @@
}
public void testStopPreviousRingtone() {
+ if (isTV()) {
+ return;
+ }
if (!hasAudioOutput()) {
Log.i(TAG, "Skipping testStopPreviousRingtone(): device doesn't have audio output.");
return;
diff --git a/tests/tests/media/src/android/media/cts/RingtoneTest.java b/tests/tests/media/src/android/media/cts/RingtoneTest.java
index 1477f3f..31ae5bb 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneTest.java
@@ -107,10 +107,18 @@
private boolean hasAudioOutput() {
return getInstrumentation().getContext().getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+ .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+ }
+
+ private boolean isTV() {
+ return getInstrumentation().getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
}
public void testRingtone() {
+ if (isTV()) {
+ return;
+ }
if (!hasAudioOutput()) {
Log.i(TAG, "Skipping testRingtone(): device doesn't have audio output.");
return;
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 5b989cc..e22d8a7 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -332,7 +332,8 @@
}
}
- public void testBuffering() throws Throwable {
+ // TODO: unhide this test when we sort out how to expose buffering control API.
+ private void doTestBuffering() throws Throwable {
final String name = "ringer.mp3";
mServer = new CtsTestServer(mContext);
try {
diff --git a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java b/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
index 888b3d4..9f90a75 100644
--- a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
+++ b/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
@@ -45,10 +45,6 @@
MEDIA_ID_CHILDREN_DELAYED
};
- static final String SEARCH_QUERY = "test_media_children";
- static final String SEARCH_QUERY_FOR_NO_RESULT = "query no result";
- static final String SEARCH_QUERY_FOR_ERROR = "query for error";
-
static StubMediaBrowserService sInstance;
/* package private */ static MediaSession sSession;
@@ -76,8 +72,10 @@
public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
List<MediaItem> mediaItems = new ArrayList<>();
if (MEDIA_ID_ROOT.equals(parentMediaId)) {
+ Bundle rootHints = getBrowserRootHints();
for (String id : MEDIA_ID_CHILDREN) {
- mediaItems.add(createMediaItem(id));
+ mediaItems.add(new MediaItem(new MediaDescription.Builder()
+ .setMediaId(id).setExtras(rootHints).build(), MediaItem.FLAG_BROWSABLE));
}
result.sendResult(mediaItems);
} else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentMediaId)) {
@@ -101,7 +99,9 @@
for (String id : MEDIA_ID_CHILDREN) {
if (id.equals(itemId)) {
- result.sendResult(createMediaItem(id));
+ result.sendResult(new MediaItem(new MediaDescription.Builder()
+ .setMediaId(id).setExtras(getBrowserRootHints()).build(),
+ MediaItem.FLAG_BROWSABLE));
return;
}
}
@@ -109,27 +109,6 @@
super.onLoadItem(itemId, result);
}
- @Override
- public void onSearch(String query, Bundle extras, Result<List<MediaItem>> result) {
- if (result == null) {
- // called the callback to mark as tested
- return;
- }
- if (SEARCH_QUERY_FOR_NO_RESULT.equals(query)) {
- result.sendResult(Collections.<MediaItem>emptyList());
- } else if (SEARCH_QUERY_FOR_ERROR.equals(query)) {
- result.sendResult(null);
- } else if (SEARCH_QUERY.equals(query)) {
- List<MediaItem> items = new ArrayList<>();
- for (String id : MEDIA_ID_CHILDREN) {
- if (id.contains(query)) {
- items.add(createMediaItem(id));
- }
- }
- result.sendResult(items);
- }
- }
-
public void sendDelayedNotifyChildrenChanged() {
if (mPendingLoadChildrenResult != null) {
mPendingLoadChildrenResult.sendResult(Collections.<MediaItem>emptyList());
@@ -147,10 +126,4 @@
mPendingLoadItemResult = null;
}
}
-
- private MediaItem createMediaItem(String id) {
- return new MediaItem(new MediaDescription.Builder()
- .setMediaId(id).setExtras(getBrowserRootHints()).build(),
- MediaItem.FLAG_BROWSABLE);
- }
}
diff --git a/tests/tests/media/src/android/media/cts/Utils.java b/tests/tests/media/src/android/media/cts/Utils.java
index e8ceeae..fb461fe 100644
--- a/tests/tests/media/src/android/media/cts/Utils.java
+++ b/tests/tests/media/src/android/media/cts/Utils.java
@@ -20,15 +20,28 @@
import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+import android.media.MediaPlayer;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.provider.Settings;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
import java.util.Scanner;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Assert;
public class Utils {
+ private static final String TAG = "CtsMediaTestUtil";
+ private static final int TEST_TIMING_TOLERANCE_MS = 50;
+
public static void enableAppOps(String packageName, String operation,
Instrumentation instrumentation) {
setAppOps(packageName, operation, instrumentation, true);
@@ -113,4 +126,53 @@
}
uiAutomation.destroy();
}
+
+ /**
+ * Assert that a media playback is started and an active {@link AudioPlaybackConfiguration}
+ * is created once. The playback will be stopped immediately after that.
+ * <p>For a media session to receive media button events, an actual playback is needed.
+ */
+ static void assertMediaPlaybackStarted(Context context) {
+ final AudioManager am = new AudioManager(context);
+ final HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ final TestAudioPlaybackCallback callback = new TestAudioPlaybackCallback();
+ MediaPlayer mediaPlayer = null;
+
+ try {
+ final int activeConfigSizeBeforeStart = am.getActivePlaybackConfigurations().size();
+ final Handler handler = new Handler(handlerThread.getLooper());
+
+ am.registerAudioPlaybackCallback(callback, handler);
+ mediaPlayer = MediaPlayer.create(context, R.raw.sine1khzs40dblong);
+ mediaPlayer.start();
+ if (!callback.mCountDownLatch.await(TEST_TIMING_TOLERANCE_MS, TimeUnit.MILLISECONDS)
+ || callback.mActiveConfigSize != activeConfigSizeBeforeStart + 1) {
+ Assert.fail("Failed to create an active AudioPlaybackConfiguration");
+ }
+ } catch (InterruptedException e) {
+ Assert.fail("Failed to create an active AudioPlaybackConfiguration");
+ } finally {
+ am.unregisterAudioPlaybackCallback(callback);
+ if (mediaPlayer != null) {
+ mediaPlayer.stop();
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ handlerThread.quitSafely();
+ }
+ }
+
+ private static class TestAudioPlaybackCallback extends AudioManager.AudioPlaybackCallback {
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+ private int mActiveConfigSize;
+
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ // For non-framework apps, only anonymized active AudioPlaybackCallbacks will be
+ // notified.
+ mActiveConfigSize = configs.size();
+ mCountDownLatch.countDown();
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/VolumeShaperTest.java b/tests/tests/media/src/android/media/cts/VolumeShaperTest.java
index 8206ecb..fce8c80 100644
--- a/tests/tests/media/src/android/media/cts/VolumeShaperTest.java
+++ b/tests/tests/media/src/android/media/cts/VolumeShaperTest.java
@@ -45,7 +45,7 @@
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { 0.f, 0.f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
// Duck configurations go from 1.f down to 0.2f (not full ramp down).
@@ -54,28 +54,28 @@
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { 1.f, 0.2f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
// Ramp configurations go from 0.f up to 1.f
private static final VolumeShaper.Configuration LINEAR_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.LINEAR_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration CUBIC_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.CUBIC_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration SINE_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.SINE_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration SCURVE_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.SCURVE_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
// internal use only
@@ -85,7 +85,7 @@
.setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_VOLUME_IN_DBFS)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { -80.f, 0.f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration[] ALL_STANDARD_RAMPS = {
@@ -101,7 +101,7 @@
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC_MONOTONIC)
.setCurve(new float[] { 0.f, 0.3f, 0.7f, 1.f } /* times */,
new float[] { 0.f, 0.5f, 0.5f, 1.f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration MONOTONIC_TEST_FAIL =
@@ -266,7 +266,7 @@
final VolumeShaper.Configuration config =
new VolumeShaper.Configuration.Builder()
.setCurve(ohOne, ohOne)
- .setDurationMs(-1.)
+ .setDurationMillis(-1.)
.build();
fail(TEST_NAME + " configuration builder should fail on invalid duration");
} catch (IllegalArgumentException e) {
@@ -291,7 +291,7 @@
assertEquals(TEST_NAME + " default interpolation should be cubic",
VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC, config.getInterpolatorType());
assertEquals(TEST_NAME + " default duration should be 1000 ms",
- 1000., config.getDurationMs());
+ 1000., config.getDurationMillis());
assertTrue(TEST_NAME + " times should be { 0.f, 1.f }",
Arrays.equals(ohOne, config.getTimes()));
assertTrue(TEST_NAME + " volumes should be { 0.f, 1.f }",
@@ -319,7 +319,7 @@
checkEqual(TEST_NAME, testRamp, ramp);
ramp = new VolumeShaper.Configuration.Builder(testRamp)
- .setDurationMs(10)
+ .setDurationMillis(10)
.build();
checkNotEqual(TEST_NAME, testRamp, ramp);
@@ -563,7 +563,7 @@
// we join several LINEAR_RAMPS together - this should effectively
// be one long LINEAR_RAMP.
volumeShaper.replace(new VolumeShaper.Configuration.Builder(LINEAR_RAMP)
- .setDurationMs((double)(duration - i))
+ .setDurationMillis((double)(duration - i))
.build(),
VolumeShaper.Operation.PLAY, true /* join */);
assertEquals(TEST_NAME + " linear ramp should continue on join",
diff --git a/tests/tests/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index af46aee..e37df49 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -27,7 +27,9 @@
frameworks/av/media/libaaudio/include
LOCAL_SRC_FILES := \
- src/test_aaudio.cpp
+ src/test_aaudio.cpp \
+ src/test_aaudio_misc.cpp \
+ src/test_aaudio_callback.cpp
LOCAL_SHARED_LIBRARIES := \
libaaudio \
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
index 77c91e4..37b434e 100644
--- a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
@@ -21,17 +21,9 @@
#include <utils/Log.h>
#include <aaudio/AAudio.h>
-#include <aaudio/AAudioDefinitions.h>
+#include "test_aaudio.h"
-
-#define NANOS_PER_MICROSECOND ((int64_t)1000)
-#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
-#define MILLIS_PER_SECOND 1000
-#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
-
-#define DEFAULT_STATE_TIMEOUT (500 * NANOS_PER_MILLISECOND)
-
-static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+int64_t getNanoseconds(clockid_t clockId) {
struct timespec time;
int result = clock_gettime(clockId, &time);
if (result < 0) {
@@ -136,10 +128,12 @@
// Check to see what kind of stream we actually got.
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
- ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000); // TODO what is range?
+ ASSERT_GE(actualSampleRate, 44100);
+ ASSERT_LE(actualSampleRate, 96000); // TODO what is min/max?
actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
- ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+ ASSERT_GE(actualSamplesPerFrame, 1);
+ ASSERT_LE(actualSamplesPerFrame, 16); // TODO what is min/max?
actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
@@ -151,7 +145,8 @@
// ASSERT_NE(AAUDIO_DEVICE_UNSPECIFIED, AAudioStream_getDeviceId(aaudioStream));
framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
- ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+ ASSERT_GE(framesPerBurst, 16);
+ ASSERT_LE(framesPerBurst, 10000); // TODO what is min/max?
// Allocate a buffer for the audio data.
// TODO handle possibility of other data formats
@@ -270,10 +265,13 @@
aaudioFramesRead = AAudioStream_getFramesRead(aaudioStream);
EXPECT_EQ(aaudioFramesRead, aaudioFramesWritten);
+ sleep(1); // FIXME - The write returns 0 if we remove this sleep! Why?
+
// The buffer should be empty after a flush so we should be able to write.
framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
// There should be some room for priming the buffer.
- ASSERT_TRUE(framesWritten > 0 && framesWritten <= framesPerBurst);
+ ASSERT_GT(framesWritten, 0);
+ ASSERT_LE(framesWritten, framesPerBurst);
EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
free(data);
@@ -291,60 +289,6 @@
}
*/
-#define AAUDIO_THREAD_ANSWER 1826375
-#define AAUDIO_THREAD_DURATION_MSEC 500
-
-static void *TestAAudioStreamThreadProc(void *arg) {
- AAudioStream* aaudioStream = (AAudioStream*) reinterpret_cast<size_t>(arg);
- aaudio_stream_state_t state;
-
- // Use this to sleep by waiting for something that won't happen.
- state = AAudioStream_getState(aaudioStream);
- AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state,
- AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND);
- return reinterpret_cast<void *>(AAUDIO_THREAD_ANSWER);
-}
-
-// Test creating a stream related thread.
-TEST(test_aaudio, aaudio_stream_thread_basic) {
- AAudioStreamBuilder *aaudioBuilder = nullptr;
- AAudioStream *aaudioStream = nullptr;
- aaudio_result_t result = AAUDIO_OK;
- void *threadResult;
-
- // Use an AAudioStreamBuilder to define the stream.
- result = AAudio_createStreamBuilder(&aaudioBuilder);
- ASSERT_EQ(AAUDIO_OK, result);
-
- // Create an AAudioStream using the Builder.
- ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
-
- // Start a thread.
- ASSERT_EQ(AAUDIO_OK, AAudioStream_createThread(aaudioStream,
- 10 * NANOS_PER_MILLISECOND,
- TestAAudioStreamThreadProc,
- reinterpret_cast<void *>(aaudioStream)));
- // Thread already started.
- ASSERT_NE(AAUDIO_OK, AAudioStream_createThread(aaudioStream, // should fail!
- 10 * NANOS_PER_MILLISECOND,
- TestAAudioStreamThreadProc,
- reinterpret_cast<void *>(aaudioStream)));
-
- // Wait for the thread to finish.
- ASSERT_EQ(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,
- &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND));
- // The thread returns a special answer.
- ASSERT_EQ(AAUDIO_THREAD_ANSWER, (int)reinterpret_cast<size_t>(threadResult));
-
- // Thread should already be joined.
- ASSERT_NE(AAUDIO_OK, AAudioStream_joinThread(aaudioStream, // should fail!
- &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND));
-
- // Cleanup
- EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
- EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-}
-
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.h b/tests/tests/nativemedia/aaudio/src/test_aaudio.h
new file mode 100644
index 0000000..dbb111d
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 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 CTS_MEDIA_TEST_AAUDIO_H
+#define CTS_MEDIA_TEST_AAUDIO_H
+
+#define NANOS_PER_MICROSECOND ((int64_t)1000)
+#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
+#define MILLIS_PER_SECOND 1000
+#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
+
+#define DEFAULT_STATE_TIMEOUT (500 * NANOS_PER_MILLISECOND)
+
+int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC);
+
+#endif //CTS_MEDIA_TEST_AAUDIO_H
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
new file mode 100644
index 0000000..2ec1e1c
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AAudioTest"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+#include "test_aaudio.h"
+
+typedef struct AAudioCallbackTestData {
+ int32_t callbackCount;
+ int32_t expectedFramesPerCallback;
+ int32_t actualFramesPerCallback;
+} AAudioCallbackTestData;
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t MyDataCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ void *audioData,
+ int32_t numFrames
+) {
+ AAudioCallbackTestData *myData = (AAudioCallbackTestData *) userData;
+
+ if (numFrames != myData->expectedFramesPerCallback) {
+ // record unexpected framecounts
+ myData->actualFramesPerCallback = numFrames;
+ } else if (myData->actualFramesPerCallback == 0) {
+ // record at least one frame count
+ myData->actualFramesPerCallback = numFrames;
+ }
+ int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+ int32_t numSamples = samplesPerFrame * numFrames;
+ if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_I16) {
+ int16_t *shortData = (int16_t *) audioData;
+ for (int i = 0; i < numSamples; i++) *shortData++ = 0;
+ } else if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_FLOAT) {
+ float *floatData = (float *) audioData;
+ for (int i = 0; i < numSamples; i++) *floatData++ = 0.0f;
+ }
+ myData->callbackCount++;
+ return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+// Test Writing to an AAudioStream using a Callback
+void runtest_aaudio_callback(aaudio_sharing_mode_t requestedSharingMode,
+ int32_t framesPerDataCallback) {
+ AAudioCallbackTestData myTestData = { 0, 0, 0 };
+ const int32_t requestedSampleRate = 48000;
+ const int32_t requestedSamplesPerFrame = 2;
+ const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
+
+ int32_t actualSampleRate = -1;
+ int32_t actualSamplesPerFrame = -1;
+ aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_INVALID;
+ aaudio_sharing_mode_t actualSharingMode;
+ int32_t framesPerBurst = -1;
+ int32_t actualBufferSize = 0;
+ int32_t actualFramesPerDataCallback = 0;
+
+ aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
+ AAudioStreamBuilder *builder = nullptr;
+ AAudioStream *stream = nullptr;
+
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Use an AAudioStreamBuilder to define the stream.
+ result = AAudio_createStreamBuilder(&builder);
+ ASSERT_EQ(AAUDIO_OK, result);
+
+ // Request stream properties.
+ AAudioStreamBuilder_setDeviceId(builder, AAUDIO_DEVICE_UNSPECIFIED);
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+ AAudioStreamBuilder_setSampleRate(builder, requestedSampleRate);
+ AAudioStreamBuilder_setSamplesPerFrame(builder, requestedSamplesPerFrame);
+ AAudioStreamBuilder_setFormat(builder, requestedDataFormat);
+ AAudioStreamBuilder_setSharingMode(builder, requestedSharingMode);
+ AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2000);
+
+ AAudioStreamBuilder_setDataCallback(builder, MyDataCallbackProc, &myTestData);
+ if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+ AAudioStreamBuilder_setFramesPerDataCallback(builder, framesPerDataCallback);
+ }
+
+ // Create an AAudioStream using the Builder.
+ ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(builder, &stream));
+ EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(builder));
+
+ EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, AAudioStream_getState(stream));
+ EXPECT_EQ(AAUDIO_DIRECTION_OUTPUT, AAudioStream_getDirection(stream));
+
+ // Check to see what kind of stream we actually got.
+ actualSampleRate = AAudioStream_getSampleRate(stream);
+ ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000); // TODO what is range?
+
+ actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+ ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+
+ actualSharingMode = AAudioStream_getSharingMode(stream);
+ ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
+ || actualSharingMode == AAUDIO_SHARING_MODE_SHARED);
+
+ actualDataFormat = AAudioStream_getFormat(stream);
+
+ // TODO test this on full build
+ // ASSERT_NE(AAUDIO_DEVICE_UNSPECIFIED, AAudioStream_getDeviceId(stream));
+
+ framesPerBurst = AAudioStream_getFramesPerBurst(stream);
+ ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+
+ actualFramesPerDataCallback = AAudioStream_getFramesPerDataCallback(stream);
+ if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+ ASSERT_EQ(framesPerDataCallback, actualFramesPerDataCallback);
+ }
+
+ actualBufferSize = AAudioStream_getBufferSizeInFrames(stream);
+ actualBufferSize = AAudioStream_setBufferSizeInFrames(stream, actualBufferSize);
+ ASSERT_TRUE(actualBufferSize > 0);
+
+ // Start/stop more than once to see if it fails after the first time.
+ // Write some data and measure the rate to see if the timing is OK.
+ for (int loopIndex = 0; loopIndex < 2; loopIndex++) {
+ myTestData.callbackCount = 0;
+ myTestData.expectedFramesPerCallback = actualFramesPerDataCallback;
+
+ // Start and wait for server to respond.
+ ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(stream));
+ ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+ AAUDIO_STREAM_STATE_STARTING,
+ &state,
+ DEFAULT_STATE_TIMEOUT));
+ EXPECT_EQ(AAUDIO_STREAM_STATE_STARTED, state);
+
+ sleep(2);
+
+ // For more coverage, alternate pausing and stopping.
+ if ((loopIndex & 1) == 0) {
+ // Request async pause and wait for server to say that it has completed the request.
+ ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(stream));
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+ AAUDIO_STREAM_STATE_PAUSING,
+ &state,
+ DEFAULT_STATE_TIMEOUT));
+ EXPECT_EQ(AAUDIO_STREAM_STATE_PAUSED, state);
+ } else {
+ // Request async stop and wait for server to say that it has completed the request.
+ ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStop(stream));
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+ AAUDIO_STREAM_STATE_STOPPING,
+ &state,
+ DEFAULT_STATE_TIMEOUT));
+ EXPECT_EQ(AAUDIO_STREAM_STATE_STOPPED, state);
+ }
+
+ int32_t oldCallbackCount = myTestData.callbackCount;
+ EXPECT_GT(oldCallbackCount, 10);
+ sleep(1);
+ EXPECT_EQ(oldCallbackCount, myTestData.callbackCount); // expect not advancing
+
+ if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+ ASSERT_EQ(framesPerDataCallback, myTestData.actualFramesPerCallback);
+ }
+ }
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_close(stream));
+}
+
+// Test Using an AAudioStream callback in SHARED mode.
+
+TEST(test_aaudio, aaudio_callback_shared_unspecified) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, AAUDIO_UNSPECIFIED);
+}
+
+TEST(test_aaudio, aaudio_callback_shared_109) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, 109); // arbitrary prime number < 192
+}
+
+TEST(test_aaudio, aaudio_callback_shared_223) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, 223); // arbitrary prime number > 192
+}
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
new file mode 100644
index 0000000..a26f17a
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AAudioTest"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <aaudio/AAudio.h>
+
+// Make sure enums do not change value.
+TEST(test_aaudio_misc, aaudio_freeze_enums) {
+
+ ASSERT_EQ(0, AAUDIO_DIRECTION_OUTPUT);
+ ASSERT_EQ(1, AAUDIO_DIRECTION_INPUT);
+
+ ASSERT_EQ(-1, AAUDIO_FORMAT_INVALID);
+ ASSERT_EQ(0, AAUDIO_FORMAT_UNSPECIFIED);
+ ASSERT_EQ(1, AAUDIO_FORMAT_PCM_I16);
+ ASSERT_EQ(2, AAUDIO_FORMAT_PCM_FLOAT);
+ ASSERT_EQ(3, AAUDIO_FORMAT_PCM_I8_24);
+ ASSERT_EQ(4, AAUDIO_FORMAT_PCM_I32);
+
+ ASSERT_EQ(0, AAUDIO_OK);
+ ASSERT_EQ(-900, AAUDIO_ERROR_BASE);
+ ASSERT_EQ(-899, AAUDIO_ERROR_DISCONNECTED);
+ ASSERT_EQ(-898, AAUDIO_ERROR_ILLEGAL_ARGUMENT);
+ ASSERT_EQ(-897, AAUDIO_ERROR_INCOMPATIBLE);
+ ASSERT_EQ(-896, AAUDIO_ERROR_INTERNAL);
+ ASSERT_EQ(-895, AAUDIO_ERROR_INVALID_STATE);
+ ASSERT_EQ(-894, AAUDIO_ERROR_UNEXPECTED_STATE);
+ ASSERT_EQ(-893, AAUDIO_ERROR_UNEXPECTED_VALUE);
+ ASSERT_EQ(-892, AAUDIO_ERROR_INVALID_HANDLE);
+ ASSERT_EQ(-891, AAUDIO_ERROR_INVALID_QUERY);
+ ASSERT_EQ(-890, AAUDIO_ERROR_UNIMPLEMENTED);
+ ASSERT_EQ(-889, AAUDIO_ERROR_UNAVAILABLE);
+ ASSERT_EQ(-888, AAUDIO_ERROR_NO_FREE_HANDLES);
+ ASSERT_EQ(-887, AAUDIO_ERROR_NO_MEMORY);
+ ASSERT_EQ(-886, AAUDIO_ERROR_NULL);
+ ASSERT_EQ(-885, AAUDIO_ERROR_TIMEOUT);
+ ASSERT_EQ(-884, AAUDIO_ERROR_WOULD_BLOCK);
+ ASSERT_EQ(-883, AAUDIO_ERROR_INVALID_FORMAT);
+ ASSERT_EQ(-882, AAUDIO_ERROR_OUT_OF_RANGE);
+ ASSERT_EQ(-881, AAUDIO_ERROR_NO_SERVICE);
+
+ ASSERT_EQ(0, AAUDIO_STREAM_STATE_UNINITIALIZED);
+ ASSERT_EQ(1, AAUDIO_STREAM_STATE_UNKNOWN);
+ ASSERT_EQ(2, AAUDIO_STREAM_STATE_OPEN);
+ ASSERT_EQ(3, AAUDIO_STREAM_STATE_STARTING);
+ ASSERT_EQ(4, AAUDIO_STREAM_STATE_STARTED);
+ ASSERT_EQ(5, AAUDIO_STREAM_STATE_PAUSING);
+ ASSERT_EQ(6, AAUDIO_STREAM_STATE_PAUSED);
+ ASSERT_EQ(7, AAUDIO_STREAM_STATE_FLUSHING);
+ ASSERT_EQ(8, AAUDIO_STREAM_STATE_FLUSHED);
+ ASSERT_EQ(9, AAUDIO_STREAM_STATE_STOPPING);
+ ASSERT_EQ(10, AAUDIO_STREAM_STATE_STOPPED);
+ ASSERT_EQ(11, AAUDIO_STREAM_STATE_CLOSING);
+ ASSERT_EQ(12, AAUDIO_STREAM_STATE_CLOSED);
+
+ ASSERT_EQ(0, AAUDIO_SHARING_MODE_EXCLUSIVE);
+ ASSERT_EQ(1, AAUDIO_SHARING_MODE_SHARED);
+
+ ASSERT_EQ(0, AAUDIO_CALLBACK_RESULT_CONTINUE);
+ ASSERT_EQ(1, AAUDIO_CALLBACK_RESULT_STOP);
+}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 24871ca..83f087b 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -45,12 +45,15 @@
import com.android.internal.telephony.PhoneConstants;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.InetSocketAddress;
import java.util.HashMap;
+import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -74,6 +77,17 @@
"Host: " + TEST_HOST + "\r\n" +
"Connection: keep-alive\r\n\r\n";
+ // Base path for IPv6 sysctls
+ private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf";
+
+ // Expected values for MIN|MAX_PLEN.
+ private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN = 48;
+ private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN = 64;
+
+ // Expected values for RFC 7559 router soliciations.
+ // Maximum number of router solicitations to send. -1 means no limit.
+ private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1;
+
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
private static final String NETWORK_CALLBACK_ACTION =
"ConnectivityManagerTest.NetworkCallbackAction";
@@ -91,6 +105,7 @@
private PackageManager mPackageManager;
private final HashMap<Integer, NetworkConfig> mNetworks =
new HashMap<Integer, NetworkConfig>();
+ boolean mWifiConnectAttempted;
@Override
protected void setUp() throws Exception {
@@ -99,6 +114,7 @@
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mPackageManager = mContext.getPackageManager();
+ mWifiConnectAttempted = false;
// Get com.android.internal.R.array.networkAttributes
int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
@@ -116,6 +132,27 @@
}
}
+ @Override
+ protected void tearDown() throws Exception {
+ // Return WiFi to its original disabled state after tests that explicitly connect.
+ if (mWifiConnectAttempted) {
+ disconnectFromWifi(null);
+ }
+ }
+
+ /**
+ * Make sure WiFi is connected to an access point if it is not already. If
+ * WiFi is enabled as a result of this function, it will be disabled
+ * automatically in tearDown().
+ */
+ private Network ensureWifiConnected() {
+ if (mWifiManager.isWifiEnabled()) {
+ return getWifiNetwork();
+ }
+ mWifiConnectAttempted = true;
+ return connectToWifi();
+ }
+
public void testIsNetworkTypeValid() {
assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE));
assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI));
@@ -298,14 +335,10 @@
final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
- final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
Network wifiNetwork = null;
try {
- // Make sure WiFi is connected to an access point to start with.
- if (!previousWifiEnabledState) {
- connectToWifi();
- }
+ ensureWifiConnected();
// Now we should expect to get a network callback about availability of the wifi
// network even if it was already connected as a state-based action when the callback
@@ -321,11 +354,6 @@
} finally {
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultTrackingCallback);
-
- // Return WiFi to its original enabled/disabled state.
- if (!previousWifiEnabledState) {
- disconnectFromWifi(wifiNetwork);
- }
}
}
@@ -357,13 +385,8 @@
// We will register for a WIFI network being available or lost.
mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
- final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
-
try {
- // Make sure WiFi is connected to an access point to start with.
- if (!previousWifiEnabledState) {
- connectToWifi();
- }
+ ensureWifiConnected();
// Now we expect to get the Intent delivered notifying of the availability of the wifi
// network even if it was already connected as a state-based action when the callback
@@ -376,11 +399,6 @@
mCm.unregisterNetworkCallback(pendingIntent);
pendingIntent.cancel();
mContext.unregisterReceiver(receiver);
-
- // Return WiFi to its original enabled/disabled state.
- if (!previousWifiEnabledState) {
- disconnectFromWifi(null);
- }
}
}
@@ -761,4 +779,42 @@
fail("No exception thrown when restricted network requested.");
} catch (SecurityException expected) {}
}
+
+ private Scanner makeWifiSysctlScanner(String key) throws FileNotFoundException {
+ Network network = ensureWifiConnected();
+ String iface = mCm.getLinkProperties(network).getInterfaceName();
+ String path = IPV6_SYSCTL_DIR + "/" + iface + "/" + key;
+ return new Scanner(new File(path));
+ }
+
+ /** Verify that accept_ra_rt_info_min_plen exists and is set to the expected value */
+ public void testAcceptRaRtInfoMinPlen() throws Exception {
+ Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_min_plen");
+ assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN, s.nextInt());
+ }
+
+ /** Verify that accept_ra_rt_info_max_plen exists and is set to the expected value */
+ public void testAcceptRaRtInfoMaxPlen() throws Exception {
+ Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_max_plen");
+ assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN, s.nextInt());
+ }
+
+ /** Verify that router_solicitations exists and is set to the expected value */
+ public void testRouterSolicitations() throws Exception {
+ Scanner s = makeWifiSysctlScanner("router_solicitations");
+ assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, s.nextInt());
+ }
+
+ /** Verify that router_solicitation_max_interval exists and is in an acceptable interval */
+ public void testRouterSolicitationMaxInterval() throws Exception {
+ Scanner s = makeWifiSysctlScanner("router_solicitation_max_interval");
+ int interval = s.nextInt();
+ // Verify we're in the interval [15 minutes, 60 minutes]. Lower values may adversely
+ // impact battery life and higher values can decrease the probability of detecting
+ // network changes.
+ final int lowerBoundSec = 15 * 60;
+ final int upperBoundSec = 60 * 60;
+ assertTrue(lowerBoundSec <= interval);
+ assertTrue(interval <= upperBoundSec);
+ }
}
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
index 93b5c44..39d683d 100644
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
@@ -85,8 +85,7 @@
randomSpi =
mISM.reserveSecurityParameterIndex(
IpSecTransform.DIRECTION_OUT,
- addr,
- IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+ addr);
assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
droidSpi =
@@ -121,8 +120,7 @@
IpSecManager.SecurityParameterIndex outSpi =
mISM.reserveSecurityParameterIndex(
IpSecTransform.DIRECTION_OUT,
- local,
- IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+ local);
IpSecManager.SecurityParameterIndex inSpi =
mISM.reserveSecurityParameterIndex(
@@ -133,21 +131,21 @@
.setSpi(IpSecTransform.DIRECTION_OUT, outSpi)
.setEncryption(
IpSecTransform.DIRECTION_OUT,
- new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY))
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
.setAuthentication(
IpSecTransform.DIRECTION_OUT,
new IpSecAlgorithm(
- IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256,
+ IpSecAlgorithm.AUTH_HMAC_SHA256,
AUTH_KEY,
AUTH_KEY.length * 8))
.setSpi(IpSecTransform.DIRECTION_IN, inSpi)
.setEncryption(
IpSecTransform.DIRECTION_IN,
- new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY))
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
.setAuthentication(
IpSecTransform.DIRECTION_IN,
new IpSecAlgorithm(
- IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256,
+ IpSecAlgorithm.AUTH_HMAC_SHA256,
AUTH_KEY,
CRYPT_KEY.length * 8))
.buildTransportModeTransform(local);
diff --git a/tests/tests/os/src/android/os/cts/AbiTest.java b/tests/tests/os/src/android/os/cts/AbiTest.java
index 49ff8aa..1765ae7 100644
--- a/tests/tests/os/src/android/os/cts/AbiTest.java
+++ b/tests/tests/os/src/android/os/cts/AbiTest.java
@@ -16,11 +16,14 @@
package android.os.cts;
+import android.system.OsConstants;
+import android.system.ErrnoException;
import android.util.ArraySet;
import com.android.compatibility.common.util.ReadElf;
import java.io.File;
+import java.io.IOException;
import java.util.Arrays;
import junit.framework.TestCase;
@@ -74,6 +77,14 @@
elf = ReadElf.read(f);
} catch (IllegalArgumentException ignored) {
// If it's not actually an ELF file, we don't care.
+ } catch (IOException ex) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof ErrnoException) {
+ // if we are denied access to the file, ignore.
+ if (((ErrnoException) cause).errno != OsConstants.EACCES) {
+ throw ex;
+ }
+ }
} finally {
if (elf != null) {
elf.close();
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index 1db2d72..736e0f3 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -53,6 +53,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import junit.framework.AssertionFailedError;
@@ -256,6 +257,32 @@
assertStorageVolumesEquals(primary, childVolume);
}
+ private void assertNoUuid(File file) {
+ try {
+ final UUID uuid = mStorageManager.getUuidForPath(file);
+ fail("Unexpected UUID " + uuid + " for " + file);
+ } catch (IOException expected) {
+ }
+ }
+
+ public void testGetUuidForPath() throws Exception {
+ assertEquals(StorageManager.UUID_DEFAULT,
+ mStorageManager.getUuidForPath(Environment.getDataDirectory()));
+ assertEquals(StorageManager.UUID_DEFAULT,
+ mStorageManager.getUuidForPath(mContext.getDataDir()));
+
+ final UUID extUuid = mStorageManager
+ .getUuidForPath(Environment.getExternalStorageDirectory());
+ if (Environment.isExternalStorageEmulated()) {
+ assertEquals(StorageManager.UUID_DEFAULT, extUuid);
+ }
+
+ assertEquals(extUuid, mStorageManager.getUuidForPath(mContext.getExternalCacheDir()));
+
+ assertNoUuid(new File("/"));
+ assertNoUuid(new File("/proc/"));
+ }
+
private static class TestProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
final byte[] bytes;
int fsyncCount;
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index ac7d703..0318610 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -787,86 +787,6 @@
insecure.isEmpty());
}
- private static final Set<File> CHAR_DEV_EXCEPTIONS = new HashSet<File>(
- Arrays.asList(
- // All exceptions should be alphabetical and associated with a bug number.
- new File("/dev/adsprpc-smd"), // b/11710243
- new File("/dev/alarm"), // b/9035217
- new File("/dev/ashmem"),
- new File("/dev/binder"),
- new File("/dev/card0"), // b/13159510
- new File("/dev/renderD128"),
- new File("/dev/renderD129"), // b/23798677
- new File("/dev/dri/card0"), // b/13159510
- new File("/dev/dri/renderD128"),
- new File("/dev/dri/renderD129"), // b/23798677
- new File("/dev/felica"), // b/11142586
- new File("/dev/felica_ant"), // b/11142586
- new File("/dev/felica_cen"), // b/11142586
- new File("/dev/felica_pon"), // b/11142586
- new File("/dev/felica_rfs"), // b/11142586
- new File("/dev/felica_rws"), // b/11142586
- new File("/dev/felica_uicc"), // b/11142586
- new File("/dev/full"),
- new File("/dev/galcore"),
- new File("/dev/genlock"), // b/9035217
- new File("/dev/graphics/galcore"),
- new File("/dev/ion"),
- new File("/dev/kgsl-2d0"), // b/11271533
- new File("/dev/kgsl-2d1"), // b/11271533
- new File("/dev/kgsl-3d0"), // b/9035217
- new File("/dev/log/events"), // b/9035217
- new File("/dev/log/main"), // b/9035217
- new File("/dev/log/radio"), // b/9035217
- new File("/dev/log/system"), // b/9035217
- new File("/dev/mali0"), // b/9106968
- new File("/dev/mali"), // b/11142586
- new File("/dev/mm_interlock"), // b/12955573
- new File("/dev/mm_isp"), // b/12955573
- new File("/dev/mm_v3d"), // b/12955573
- new File("/dev/msm_rotator"), // b/9035217
- new File("/dev/null"),
- new File("/dev/nvhost-as-gpu"),
- new File("/dev/nvhost-ctrl"), // b/9088251
- new File("/dev/nvhost-ctrl-gpu"),
- new File("/dev/nvhost-dbg-gpu"),
- new File("/dev/nvhost-gpu"),
- new File("/dev/nvhost-gr2d"), // b/9088251
- new File("/dev/nvhost-gr3d"), // b/9088251
- new File("/dev/nvhost-tsec"),
- new File("/dev/nvhost-prof-gpu"),
- new File("/dev/nvhost-vic"),
- new File("/dev/nvmap"), // b/9088251
- new File("/dev/pmsg0"), // b/31857082
- new File("/dev/ptmx"), // b/9088251
- new File("/dev/pvrsrvkm"), // b/9108170
- new File("/dev/pvr_sync"),
- new File("/dev/quadd"),
- new File("/dev/random"),
- new File("/dev/snfc_cen"), // b/11142586
- new File("/dev/snfc_hsel"), // b/11142586
- new File("/dev/snfc_intu_poll"), // b/11142586
- new File("/dev/snfc_rfs"), // b/11142586
- new File("/dev/tegra-throughput"),
- new File("/dev/tiler"), // b/9108170
- new File("/dev/tty"),
- new File("/dev/urandom"),
- new File("/dev/ump"), // b/11142586
- new File("/dev/xt_qtaguid"), // b/9088251
- new File("/dev/zero"),
- new File("/dev/fimg2d"), // b/10428016
- new File("/dev/mobicore-user") // b/10428016
- ));
-
- public void testAllCharacterDevicesAreSecure() throws Exception {
- Set<File> insecure = getAllInsecureDevicesInDirAndSubdir(new File("/dev"), FileUtils.S_IFCHR);
- Set<File> insecurePts = getAllInsecureDevicesInDirAndSubdir(new File("/dev/pts"), FileUtils.S_IFCHR);
- insecure.removeAll(CHAR_DEV_EXCEPTIONS);
- insecure.removeAll(insecurePts);
- assertTrue("Found insecure character devices: " + insecure.toString(),
- insecure.isEmpty());
- }
-
public void testDevRandomWorldReadableAndWritable() throws Exception {
File f = new File("/dev/random");
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 4e6b9ea..949e2c1 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1511,6 +1511,16 @@
<permission android:name="android.permission.DVB_DEVICE"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by carrier state
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by user state
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows reading the OEM unlock state
@hide <p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_OEM_UNLOCK_STATE"
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 198fe9f..eb394b3 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -185,9 +185,6 @@
Log.d(LOG_TAG, "setUpClass()");
sInstrumentation = InstrumentationRegistry.getInstrumentation();
- assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_PRINTING));
-
sUiDevice = UiDevice.getInstance(sInstrumentation);
// Make sure we start with a clean slate.
@@ -240,6 +237,10 @@
public void setUp() throws Exception {
Log.d(LOG_TAG, "setUp()");
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_PRINTING));
+
// Initialize the latches.
Log.d(LOG_TAG, "init counters");
mCancelOperationCounter = new CallCounter();
@@ -289,16 +290,16 @@
clearPrintSpoolerData();
Log.d(LOG_TAG, "enable animations");
- if (sWindowAnimationScaleBefore != Float.NaN) {
+ if (!Float.isNaN(sWindowAnimationScaleBefore)) {
SystemUtil.runShellCommand(sInstrumentation,
"settings put global window_animation_scale " + sWindowAnimationScaleBefore);
}
- if (sTransitionAnimationScaleBefore != Float.NaN) {
+ if (!Float.isNaN(sTransitionAnimationScaleBefore)) {
SystemUtil.runShellCommand(sInstrumentation,
"settings put global transition_animation_scale " +
sTransitionAnimationScaleBefore);
}
- if (sAnimatiorDurationScaleBefore != Float.NaN) {
+ if (!Float.isNaN(sAnimatiorDurationScaleBefore)) {
SystemUtil.runShellCommand(sInstrumentation,
"settings put global animator_duration_scale " + sAnimatiorDurationScaleBefore);
}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
index e40f2ed..d8a80d2 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
@@ -131,6 +131,14 @@
}
}
+ private void maybeClick(UiSelector sel) {
+ try { mDevice.findObject(sel).click(); } catch (Throwable ignored) { }
+ }
+
+ private void maybeClick(BySelector sel) {
+ try { mDevice.findObject(sel).click(); } catch (Throwable ignored) { }
+ }
+
/**
* Verify that whoever handles {@link MediaStore#ACTION_IMAGE_CAPTURE} can
* correctly write the contents into a passed {@code content://} Uri.
@@ -164,7 +172,7 @@
+ pkg + " " + android.Manifest.permission.ACCESS_COARSE_LOCATION);
getInstrumentation().getUiAutomation().executeShellCommand("pm grant "
+ pkg + " " + android.Manifest.permission.ACCESS_FINE_LOCATION);
- Thread.sleep(1000);
+ SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
mActivity.startActivityForResult(intent, REQUEST_CODE);
mDevice.waitForIdle();
@@ -184,15 +192,27 @@
// Hrm, that didn't work; let's try an alternative approach of digging
// around for a shutter button
if (result == null) {
- mDevice.findObject(new UiSelector().resourceId(pkg + ":id/shutter_button")).click();
+ maybeClick(new UiSelector().resourceId(pkg + ":id/shutter_button"));
mDevice.waitForIdle();
SystemClock.sleep(5 * DateUtils.SECOND_IN_MILLIS);
- mDevice.findObject(new UiSelector().resourceId(pkg + ":id/shutter_button")).click();
+ maybeClick(new UiSelector().resourceId(pkg + ":id/shutter_button"));
mDevice.waitForIdle();
+
+ result = mActivity.getResult(15, TimeUnit.SECONDS);
+ Log.d(TAG, "Second pass result was " + result);
}
- result = mActivity.getResult(15, TimeUnit.SECONDS);
- Log.d(TAG, "Second pass result was " + result);
+ // Grr, let's try hunting around even more
+ if (result == null) {
+ maybeClick(By.pkg(pkg).descContains("Capture"));
+ mDevice.waitForIdle();
+ SystemClock.sleep(5 * DateUtils.SECOND_IN_MILLIS);
+ maybeClick(By.pkg(pkg).descContains("Done"));
+ mDevice.waitForIdle();
+
+ result = mActivity.getResult(15, TimeUnit.SECONDS);
+ Log.d(TAG, "Third pass result was " + result);
+ }
assertNotNull("Expected to get a IMAGE_CAPTURE result; your camera app should "
+ "respond to the CAMERA and DPAD_CENTER keycodes", result);
diff --git a/tests/tests/security/src/android/security/cts/STKFrameworkTest.java b/tests/tests/security/src/android/security/cts/STKFrameworkTest.java
index 3b924a8..e431a6c 100644
--- a/tests/tests/security/src/android/security/cts/STKFrameworkTest.java
+++ b/tests/tests/security/src/android/security/cts/STKFrameworkTest.java
@@ -48,7 +48,7 @@
}
Intent intent = new Intent();
- intent.setAction("android.intent.action.stk.command");
+ intent.setAction("com.android.internal.stk.command");
intent.putExtra("STK CMD", "test");
ComponentName cn =
ComponentName.unflattenFromString("com.android.stk/com.android.stk.StkCmdReceiver");
@@ -56,11 +56,11 @@
try {
mContext.sendBroadcast(intent);
fail("Able to send broadcast which can be received by any app which has registered " +
- "broadcast for action 'android.intent.action.stk.command' since it is not " +
+ "broadcast for action 'com.android.internal.stk.command' since it is not " +
"protected with any permission. Device is vulnerable to CVE-2015-3843.");
} catch (SecurityException e) {
/* Pass the Test case: App should not be able to send broadcast using action
- * 'android.intent.action.stk.command' as it is protected by permission in
+ * 'com.android.internal.stk.command' as it is protected by permission in
* patched devices
*/
}
diff --git a/tests/tests/security/src/android/security/cts/SeccompTest.java b/tests/tests/security/src/android/security/cts/SeccompTest.java
index 44185bd..745aa87 100644
--- a/tests/tests/security/src/android/security/cts/SeccompTest.java
+++ b/tests/tests/security/src/android/security/cts/SeccompTest.java
@@ -67,6 +67,30 @@
}
}
+ public void testCTSSwapOnOffBlocked() {
+ if (CpuFeatures.isArm64Cpu()) {
+ testBlocked(224); // __NR_swapon
+ testBlocked(225); // __NR_swapoff
+ } else if (CpuFeatures.isArmCpu()) {
+ testBlocked(87); // __NR_swapon
+ testBlocked(115); // __NR_swapoff
+ } else if (CpuFeatures.isX86_64Cpu()) {
+ testBlocked(167); // __NR_swapon
+ testBlocked(168); // __NR_swapoff
+ } else if (CpuFeatures.isX86Cpu()) {
+ testBlocked(87); // __NR_swapon
+ testBlocked(115); // __NR_swapoff
+ } else if (CpuFeatures.isMips64Cpu()) {
+ testBlocked(5162); // __NR_swapon
+ testBlocked(5163); // __NR_swapoff
+ } else if (CpuFeatures.isMipsCpu()) {
+ testBlocked(4087); // __NR_swapon
+ testBlocked(4115); // __NR_swapoff
+ } else {
+ fail("Unsupported OS");
+ }
+ }
+
private void testBlocked(int nr) {
assertTrue("Syscall " + nr + " allowed", testSyscallBlocked(nr));
}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 199c63b..c458ffd 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -617,6 +617,7 @@
codec.release();
}
}
+ ex.unselectTrack(t);
}
ex.release();
String cve = rname.replace("_", "-").toUpperCase();
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 5ace9ff..ee1f901 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.telecom.CallAudioState;
import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import java.util.ArrayList;
@@ -68,6 +69,23 @@
}
/**
+ * Tests {@link TelecomManager#getSelfManagedPhoneAccounts()} API to ensure it returns a list of
+ * the registered self-managed {@link android.telecom.PhoneAccount}s.
+ */
+ public void testTelecomManagerGetSelfManagedPhoneAccounts() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ List<PhoneAccountHandle> phoneAccountHandles =
+ mTelecomManager.getSelfManagedPhoneAccounts();
+
+ assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
+ assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_2));
+ assertFalse(phoneAccountHandles.contains(TestUtils.TEST_PHONE_ACCOUNT_HANDLE));
+ }
+
+ /**
* Tests the ability to successfully register a self-managed
* {@link android.telecom.PhoneAccount}.
*/
@@ -348,14 +366,19 @@
waitOnAllHandlers(getInstrumentation());
}
- public void testEmergencyCallOngoing() throws Exception {
+ /**
+ * Disabled for now; there is not a reliable means of setting a phone number as a test emergency
+ * number.
+ * @throws Exception
+ */
+ public void DONOTtestEmergencyCallOngoing() throws Exception {
if (!mShouldTestTelecom) {
return;
}
+ // TODO: Need to find a reliable way to set a test emergency number.
// Set 555-1212 as a test emergency number.
- TestUtils.executeShellCommand(getInstrumentation(),
- "setprop ril.ecclist 5551212");
+ TestUtils.executeShellCommand(getInstrumentation(), "setprop ril.ecclist 5551212");
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index fbe3f54..a6404e0 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -555,7 +555,47 @@
fail("Expected SecurityException. App does not have carrier privileges or is not the "
+ "default dialer app");
} catch (SecurityException expected) {
+ }
+ }
+ /**
+ * Tests that the device properly reports the contents of EF_FPLMN or null
+ */
+ @Test
+ public void testGetForbiddenPlmns() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ String[] plmns = mTelephonyManager.getForbiddenPlmns();
+
+ int phoneType = mTelephonyManager.getPhoneType();
+ switch (phoneType) {
+ case TelephonyManager.PHONE_TYPE_GSM:
+ assertNotNull("Forbidden PLMNs must be valid or an empty list!", plmns);
+ case TelephonyManager.PHONE_TYPE_CDMA:
+ case TelephonyManager.PHONE_TYPE_NONE:
+ if (plmns == null) {
+ return;
+ }
+ }
+
+ for(String plmn : plmns) {
+ if (plmn.length() > 6 || plmn.length() < 5) {
+ fail("Invalid Length for PLMN-ID, must be 5 or 6: " + plmn);
+ }
+
+ // A record which is written in the SIM but empty will
+ // be all f's
+ if(android.text.TextUtils.isDigitsOnly(plmn)) {
+ assertTrue(
+ "PLMNs must be strings of digits 0-9,F! " + plmn,
+ android.text.TextUtils.isDigitsOnly(plmn));
+ } else {
+ for (char c : plmn.toUpperCase().toCharArray()) {
+ assertTrue("PLMNs must be strings of digits 0-9,F! " + plmn,
+ Character.toUpperCase(c) == 'F');
+ }
+ }
}
}
diff --git a/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java b/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java
index ae8ab8d..1e766ba 100644
--- a/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java
@@ -348,6 +348,10 @@
}
public void testFilter_originatingNumber_match_filtered() {
+ if (!hasTelephony(mContext)) {
+ Log.d(TAG, "skipping test that requires telephony feature");
+ return;
+ }
VisualVoicemailSmsFilterSettings settings = new VisualVoicemailSmsFilterSettings.Builder()
.setClientPrefix("//CTSVVM")
.setOriginatingNumbers(Arrays.asList(mPhoneNumber))
@@ -357,6 +361,10 @@
}
public void testFilter_originatingNumber_mismatch_notFiltered() {
+ if (!hasTelephony(mContext)) {
+ Log.d(TAG, "skipping test that requires telephony feature");
+ return;
+ }
VisualVoicemailSmsFilterSettings settings = new VisualVoicemailSmsFilterSettings.Builder()
.setClientPrefix("//CTSVVM")
.setOriginatingNumbers(Arrays.asList("1"))
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
index 8ca7598..dfabe71 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
@@ -23,11 +23,15 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.Html;
+import android.text.Layout;
import android.text.SpanWatcher;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.method.SingleLineTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.text.style.AlignmentSpan;
import android.text.style.ParagraphStyle;
import android.text.style.QuoteSpan;
@@ -583,4 +587,27 @@
ParagraphStyle.class);
assertEquals(0, paragraphSpans.length);
}
+
+ @Test
+ public void testCopyConstructorDoesNotEnforceParagraphStyleConstraint() {
+ final SpannableStringBuilder original = new SpannableStringBuilder("\ntest data\nb");
+ final AlignmentSpan.Standard span = new AlignmentSpan.Standard(
+ Layout.Alignment.ALIGN_NORMAL);
+ original.setSpan(span, 1, original.length() - 1, Spanned.SPAN_PARAGRAPH);
+
+ // test that paragraph style is in the copied when it is valid
+ SpannableStringBuilder copied = new SpannableStringBuilder(original);
+ AlignmentSpan.Standard[] copiedSpans = copied.getSpans(0, copied.length(),
+ AlignmentSpan.Standard.class);
+
+ assertEquals(1, copiedSpans.length);
+
+ // test that paragraph style is in not in the copied when it is invalid
+ final TransformationMethod transformation = SingleLineTransformationMethod.getInstance();
+ final CharSequence transformed = transformation.getTransformation(original, null);
+ copied = new SpannableStringBuilder(transformed);
+ copiedSpans = copied.getSpans(0, copied.length(), AlignmentSpan.Standard.class);
+
+ assertEquals(0, copiedSpans.length);
+ }
}
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringTest.java b/tests/tests/text/src/android/text/cts/SpannableStringTest.java
index 81dbf9b..3771613 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringTest.java
@@ -16,19 +16,34 @@
package android.text.cts;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.fail;
+
import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.method.SingleLineTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.text.style.AlignmentSpan;
import android.text.style.LocaleSpan;
import android.text.style.QuoteSpan;
import android.text.style.UnderlineSpan;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Locale;
-public class SpannableStringTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableStringTest {
- @SmallTest
+ @Test
public void testConstructor() {
new SpannableString("test");
@@ -39,7 +54,7 @@
}
}
- @SmallTest
+ @Test
public void testValueOf() {
String text = "test valueOf";
SpannableString spannable = SpannableString.valueOf(text);
@@ -56,7 +71,7 @@
}
}
- @SmallTest
+ @Test
public void testSetSpan() {
String text = "hello, world";
SpannableString spannable = new SpannableString(text);
@@ -87,7 +102,7 @@
}
}
- @SmallTest
+ @Test
public void testRemoveSpan() {
SpannableString spannable = new SpannableString("hello, world");
@@ -111,7 +126,7 @@
assertEquals(0, spannable.getSpanFlags(underlineSpan));
}
- @SmallTest
+ @Test
public void testSubSequence() {
String text = "hello, world";
SpannableString spannable = new SpannableString(text);
@@ -135,7 +150,7 @@
}
}
- @SmallTest
+ @Test
public void testSubsequence_copiesSpans() {
SpannableString first = new SpannableString("t\nest data");
QuoteSpan quoteSpan = new QuoteSpan();
@@ -165,8 +180,7 @@
}
}
-
- @SmallTest
+ @Test
public void testCopyConstructor_copiesAllSpans() {
SpannableString first = new SpannableString("t\nest data");
first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
@@ -189,7 +203,7 @@
}
}
- @SmallTest
+ @Test
public void testCopyGrowable() {
SpannableString first = new SpannableString("t\nest data");
final int N_SPANS = 127;
@@ -201,4 +215,27 @@
Object[] secondSpans = second.getSpans(0, second.length(), Object.class);
assertEquals(secondSpans.length, N_SPANS + 1);
}
+
+ @Test
+ public void testCopyConstructorDoesNotEnforceParagraphStyleConstraint() {
+ final SpannableStringBuilder original = new SpannableStringBuilder("\ntest data\nb");
+ final AlignmentSpan.Standard span = new AlignmentSpan.Standard(
+ Layout.Alignment.ALIGN_NORMAL);
+ original.setSpan(span, 1, original.length() - 1, Spanned.SPAN_PARAGRAPH);
+
+ // test that paragraph style is in the copied when it is valid
+ SpannableString copied = new SpannableString(original);
+ AlignmentSpan.Standard[] copiedSpans = copied.getSpans(0, copied.length(),
+ AlignmentSpan.Standard.class);
+
+ assertEquals(1, copiedSpans.length);
+
+ // test that paragraph style is in not in the copied when it is invalid
+ final TransformationMethod transformation = SingleLineTransformationMethod.getInstance();
+ final CharSequence transformed = transformation.getTransformation(original, null);
+ copied = new SpannableString(transformed);
+ copiedSpans = copied.getSpans(0, copied.length(), AlignmentSpan.Standard.class);
+
+ assertEquals(0, copiedSpans.length);
+ }
}
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 9dca58f..308e750 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -1196,8 +1196,8 @@
assertEquals(0, layout.getLineForOffset(lineBreakOffset - 1));
assertEquals(0, layout.getOffsetForHorizontal(0, 0.0f));
- assertEquals(lineBreakOffset, layout.getOffsetForHorizontal(0, width));
- assertEquals(lineBreakOffset, layout.getOffsetForHorizontal(0, width * 2));
+ assertEquals(lineBreakOffset - 2, layout.getOffsetForHorizontal(0, width));
+ assertEquals(lineBreakOffset - 2, layout.getOffsetForHorizontal(0, width * 2));
final int lineCount = layout.getLineCount();
assertEquals(testString.length(), layout.getOffsetForHorizontal(lineCount - 1, width));
diff --git a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
index d8342ca..16f632c 100644
--- a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
@@ -111,16 +111,26 @@
@Test
public void testGetInputType() {
- final int expected = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+ // The "normal" input type that has been used consistently until Android O.
+ final int dateTimeType = InputType.TYPE_CLASS_DATETIME
+ | InputType.TYPE_DATETIME_VARIATION_DATE;
+ // Fallback for locales that need more characters.
+ final int textType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ // Deprecated constructor that needs to preserve pre-existing behavior.
DateKeyListener dateKeyListener = new DateKeyListener();
- assertEquals(expected, dateKeyListener.getInputType());
+ assertEquals(dateTimeType, dateKeyListener.getInputType());
+ // TYPE_CLASS_DATETIME is fine for English locales.
dateKeyListener = new DateKeyListener(Locale.US);
- assertEquals(expected, dateKeyListener.getInputType());
+ assertEquals(dateTimeType, dateKeyListener.getInputType());
+ dateKeyListener = new DateKeyListener(Locale.UK);
+ assertEquals(dateTimeType, dateKeyListener.getInputType());
+ // Persian needs more characters then typically provided by datetime inputs, so it falls
+ // back on normal text.
dateKeyListener = new DateKeyListener(Locale.forLanguageTag("fa-IR"));
- assertEquals(expected, dateKeyListener.getInputType());
+ assertEquals(textType, dateKeyListener.getInputType());
}
/*
diff --git a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
index 06bb68c..decd451 100644
--- a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
@@ -114,17 +114,26 @@
@Test
public void testGetInputType() {
- final int expected = InputType.TYPE_CLASS_DATETIME
+ // The "normal" input type that has been used consistently until Android O.
+ final int dateTimeType = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_NORMAL;
+ // Fallback for locales that need more characters.
+ final int textType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ // Deprecated constructor that needs to preserve pre-existing behavior.
DateTimeKeyListener listener = DateTimeKeyListener.getInstance();
- assertEquals(expected, listener.getInputType());
+ assertEquals(dateTimeType, listener.getInputType());
+ // TYPE_CLASS_DATETIME is fine for English locales.
listener = DateTimeKeyListener.getInstance(Locale.US);
- assertEquals(expected, listener.getInputType());
+ assertEquals(dateTimeType, listener.getInputType());
+ listener = DateTimeKeyListener.getInstance(Locale.UK);
+ assertEquals(dateTimeType, listener.getInputType());
+ // Persian needs more characters then typically provided by datetime inputs, so it falls
+ // back on normal text.
listener = DateTimeKeyListener.getInstance(Locale.forLanguageTag("fa-IR"));
- assertEquals(expected, listener.getInputType());
+ assertEquals(textType, listener.getInputType());
}
/*
diff --git a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
index 510d329..7854268 100644
--- a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
@@ -899,8 +899,9 @@
assertEquals(-1, acceptedChars.indexOf(usDecimalSeparator));
}
+ // Deprecated constructors that need to preserve pre-existing behavior.
@Test
- public void testGetInputType1() {
+ public void testGetInputType_deprecatedConstructors() {
DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(false, false);
int expected = InputType.TYPE_CLASS_NUMBER;
assertEquals(expected, digitsKeyListener.getInputType());
@@ -922,27 +923,57 @@
assertEquals(expected, digitsKeyListener.getInputType());
}
+ // Deprecated constructors that need to preserve pre-existing behavior.
@Test
- public void testGetInputType2() {
- final Locale irLocale = Locale.forLanguageTag("fa-IR");
- DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(irLocale, false, false);
+ public void testGetInputType_English() {
int expected = InputType.TYPE_CLASS_NUMBER;
+ DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(
+ Locale.US, false, false);
+ assertEquals(expected, digitsKeyListener.getInputType());
+ digitsKeyListener = DigitsKeyListener.getInstance(
+ Locale.UK, false, false);
assertEquals(expected, digitsKeyListener.getInputType());
- digitsKeyListener = DigitsKeyListener.getInstance(irLocale, true, false);
expected = InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_SIGNED;
+ digitsKeyListener = DigitsKeyListener.getInstance(Locale.US, true, false);
+ assertEquals(expected, digitsKeyListener.getInputType());
+ digitsKeyListener = DigitsKeyListener.getInstance(Locale.UK, true, false);
assertEquals(expected, digitsKeyListener.getInputType());
- digitsKeyListener = DigitsKeyListener.getInstance(irLocale, false, true);
expected = InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_DECIMAL;
+ digitsKeyListener = DigitsKeyListener.getInstance(Locale.US, false, true);
+ assertEquals(expected, digitsKeyListener.getInputType());
+ digitsKeyListener = DigitsKeyListener.getInstance(Locale.UK, false, true);
assertEquals(expected, digitsKeyListener.getInputType());
- digitsKeyListener = DigitsKeyListener.getInstance(irLocale, true, true);
expected = InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_SIGNED
| InputType.TYPE_NUMBER_FLAG_DECIMAL;
+ digitsKeyListener = DigitsKeyListener.getInstance(Locale.US, true, true);
+ assertEquals(expected, digitsKeyListener.getInputType());
+ digitsKeyListener = DigitsKeyListener.getInstance(Locale.UK, true, true);
+ assertEquals(expected, digitsKeyListener.getInputType());
+ }
+
+ // Persian needs more characters then typically provided by datetime inputs, so it falls
+ // back on normal text.
+ @Test
+ public void testGetInputType_Persian() {
+ final Locale irLocale = Locale.forLanguageTag("fa-IR");
+ final int expected = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+
+ DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(irLocale, false, false);
+ assertEquals(expected, digitsKeyListener.getInputType());
+
+ digitsKeyListener = DigitsKeyListener.getInstance(irLocale, true, false);
+ assertEquals(expected, digitsKeyListener.getInputType());
+
+ digitsKeyListener = DigitsKeyListener.getInstance(irLocale, false, true);
+ assertEquals(expected, digitsKeyListener.getInputType());
+
+ digitsKeyListener = DigitsKeyListener.getInstance(irLocale, true, true);
assertEquals(expected, digitsKeyListener.getInputType());
}
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index 3ed0ad4..bb4ffb6 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -17,13 +17,11 @@
package android.text.method.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.reset;
@@ -221,23 +219,6 @@
assertSame(method0, method1);
}
- @Test
- public void testOnFocusChanged() {
- // lose focus
- reset(mMethod);
- assertTrue(mEditText.isFocused());
- CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "DPAD_DOWN");
- assertFalse(mEditText.isFocused());
- verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
-
- // gain focus
- reset(mMethod);
- assertFalse(mEditText.isFocused());
- CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "DPAD_UP");
- assertTrue(mEditText.isFocused());
- verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
- }
-
private void savePasswordPref() {
try {
mPasswordPrefBackUp = System.getInt(mActivity.getContentResolver(),
diff --git a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
index 5db4a6f..ad622d0 100644
--- a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
@@ -25,7 +25,11 @@
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
+import android.text.SpannableString;
+import android.text.Spanned;
import android.text.method.SingleLineTransformationMethod;
+import android.text.style.AlignmentSpan;
import android.util.TypedValue;
import android.widget.EditText;
@@ -72,6 +76,21 @@
// TODO cannot get transformed text from the view
}
+ @Test
+ public void testSubsequence_doesNotThrowExceptionWithParagraphSpans() {
+ final SingleLineTransformationMethod method = SingleLineTransformationMethod.getInstance();
+ final SpannableString original = new SpannableString("\ntest data\nb");
+ final AlignmentSpan.Standard span = new AlignmentSpan.Standard(
+ Layout.Alignment.ALIGN_NORMAL);
+ original.setSpan(span, 1, original.length() - 1, Spanned.SPAN_PARAGRAPH);
+
+ final CharSequence transformed = method.getTransformation(original, null);
+ // expectation: should not throw an exception
+ transformed.subSequence(0, transformed.length());
+ }
+
+
+
private static class MySingleLineTranformationMethod extends SingleLineTransformationMethod {
@Override
protected char[] getOriginal() {
diff --git a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
index 68d410d..a887a19 100644
--- a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
@@ -110,17 +110,26 @@
@Test
public void testGetInputType() {
- final int expected = InputType.TYPE_CLASS_DATETIME
+ // The "normal" input type that has been used consistently until Android O.
+ final int dateTimeType = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_TIME;
+ // Fallback for locales that need more characters.
+ final int textType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ // Deprecated constructor that needs to preserve pre-existing behavior.
TimeKeyListener listener = TimeKeyListener.getInstance();
- assertEquals(expected, listener.getInputType());
+ assertEquals(dateTimeType, listener.getInputType());
+ // TYPE_CLASS_DATETIME is fine for English locales.
listener = TimeKeyListener.getInstance(Locale.US);
- assertEquals(expected, listener.getInputType());
+ assertEquals(dateTimeType, listener.getInputType());
+ listener = TimeKeyListener.getInstance(Locale.UK);
+ assertEquals(dateTimeType, listener.getInputType());
+ // Persian needs more characters then typically provided by datetime inputs, so it falls
+ // back on normal text.
listener = TimeKeyListener.getInstance(Locale.forLanguageTag("fa-IR"));
- assertEquals(expected, listener.getInputType());
+ assertEquals(textType, listener.getInputType());
}
/*
diff --git a/tests/tests/text/src/android/text/method/cts/TransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/TransformationMethodTest.java
new file mode 100644
index 0000000..d67fc59
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/TransformationMethodTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.returnsFirstArg;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.method.TransformationMethod;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test that {@link TransformationMethod} interface gets called.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TransformationMethodTest {
+ private static final int EDIT_TXT_ID = 1;
+
+ private Instrumentation mInstrumentation;
+ private CtsActivity mActivity;
+ private TransformationMethod mMethod;
+ private EditText mEditText;
+ private Button mButton;
+
+ @Rule
+ public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
+
+ @Before
+ public void setup() throws Throwable {
+ mActivity = mActivityRule.getActivity();
+ PollingCheck.waitFor(1000, mActivity::hasWindowFocus);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mMethod = mock(TransformationMethod.class);
+ when(mMethod.getTransformation(any(), any())).then(returnsFirstArg());
+
+ mActivityRule.runOnUiThread(() -> {
+ mEditText = new EditTextNoIme(mActivity);
+ mEditText.setId(EDIT_TXT_ID);
+ mEditText.setTransformationMethod(mMethod);
+ mButton = new Button(mActivity);
+ mButton.setFocusableInTouchMode(true);
+ LinearLayout layout = new LinearLayout(mActivity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(mEditText, new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ layout.addView(mButton, new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ mActivity.setContentView(layout);
+ mEditText.requestFocus();
+ });
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mEditText.isFocused());
+ }
+
+ @Test
+ public void testGetTransformation() throws Throwable {
+ reset(mMethod);
+ when(mMethod.getTransformation(any(), any())).then(returnsFirstArg());
+ mActivityRule.runOnUiThread(() -> mEditText.setText("some text"));
+ mInstrumentation.waitForIdleSync();
+ verify(mMethod, atLeastOnce()).getTransformation(any(), any());
+ }
+
+ @Test
+ public void testOnFocusChanged() throws Throwable {
+ // lose focus
+ reset(mMethod);
+ assertTrue(mEditText.isFocused());
+ mActivityRule.runOnUiThread(() -> mButton.requestFocus());
+ mInstrumentation.waitForIdleSync();
+ verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
+
+ // gain focus
+ reset(mMethod);
+ assertFalse(mEditText.isFocused());
+ mActivityRule.runOnUiThread(() -> mEditText.requestFocus());
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mEditText.isFocused());
+ verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
+ }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
index 0a14361..4b55057 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
@@ -17,19 +17,24 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import android.animation.Animator;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.transition.ChangeBounds;
import android.transition.Transition;
+import android.transition.TransitionValues;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.LinearInterpolator;
import org.junit.Before;
import org.junit.Test;
@@ -43,19 +48,22 @@
private static final int SMALL_OFFSET_DP = 2;
ChangeBounds mChangeBounds;
+ ValidateBoundsListener mBoundsChangeListener;
@Override
@Before
public void setup() {
super.setup();
resetChangeBoundsTransition();
+ mBoundsChangeListener = null;
}
private void resetChangeBoundsTransition() {
mListener = mock(Transition.TransitionListener.class);
- mChangeBounds = new ChangeBounds();
+ mChangeBounds = new MyChangeBounds();
mChangeBounds.setDuration(400);
mChangeBounds.addListener(mListener);
+ mChangeBounds.setInterpolator(new LinearInterpolator());
mTransition = mChangeBounds;
}
@@ -65,11 +73,10 @@
validateInScene1();
- startTransition(R.layout.scene6);
+ mBoundsChangeListener = new ValidateBoundsListener(true);
- // now delay for at least a few frames before checking intermediate values:
- Thread.sleep(150);
- validateNormalIntermediate();
+ startTransition(R.layout.scene6);
+ // The update listener will validate that it is changing throughout the animation
waitForEnd(400);
validateInScene6();
@@ -84,11 +91,11 @@
validateInScene1();
+ mBoundsChangeListener = new ValidateBoundsListener(true);
+
startTransition(R.layout.scene6);
- // now delay for at least a few frames before checking intermediate values:
- Thread.sleep(150);
- validateClippedIntermediate();
+ // The update listener will validate that it is changing throughout the animation
waitForEnd(400);
validateInScene6();
@@ -101,11 +108,10 @@
validateInScene6();
+ mBoundsChangeListener = new ValidateBoundsListener(false);
startTransition(R.layout.scene1);
- // now delay for at least a few frames before checking intermediate values:
- Thread.sleep(150);
- validateClippedIntermediate();
+ // The update listener will validate that it is changing throughout the animation
waitForEnd(400);
validateInScene1();
@@ -252,63 +258,6 @@
assertNull(belowSquare.getClipBounds());
}
- private void validateIntermediatePosition() {
- Resources resources = mActivity.getResources();
- float smallDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- SMALL_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- float largeDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics());
-
- View redSquare = mActivity.findViewById(R.id.redSquare);
- View greenSquare = mActivity.findViewById(R.id.greenSquare);
- assertTrue(redSquare.getTop() != 0);
- assertTrue(greenSquare.getTop() != 0);
- assertNotWithinAPixel(smallDim, redSquare.getTop());
- assertNotWithinAPixel(largeDim, redSquare.getTop());
- assertNotWithinAPixel(smallDim, greenSquare.getTop());
- assertNotWithinAPixel(largeDim, greenSquare.getTop());
- }
-
- private void validateClippedIntermediate() {
- validateIntermediatePosition();
- Resources resources = mActivity.getResources();
- float largeDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- View redSquare = mActivity.findViewById(R.id.redSquare);
- View greenSquare = mActivity.findViewById(R.id.greenSquare);
-
- assertWithinAPixel(largeDim, redSquare.getWidth());
- assertWithinAPixel(largeDim, redSquare.getHeight());
- assertWithinAPixel(largeDim, greenSquare.getWidth());
- assertWithinAPixel(largeDim, greenSquare.getHeight());
-
- assertNotNull(redSquare.getClipBounds());
- assertNotNull(greenSquare.getClipBounds());
- }
-
- private void validateNormalIntermediate() {
- validateIntermediatePosition();
- Resources resources = mActivity.getResources();
- float smallDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- SMALL_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- float largeDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- View redSquare = mActivity.findViewById(R.id.redSquare);
- View greenSquare = mActivity.findViewById(R.id.greenSquare);
- assertNotWithinAPixel(smallDim, redSquare.getWidth());
- assertNotWithinAPixel(smallDim, redSquare.getHeight());
- assertNotWithinAPixel(largeDim, redSquare.getWidth());
- assertNotWithinAPixel(largeDim, redSquare.getHeight());
-
- assertNotWithinAPixel(smallDim, greenSquare.getWidth());
- assertNotWithinAPixel(smallDim, greenSquare.getHeight());
- assertNotWithinAPixel(largeDim, greenSquare.getWidth());
- assertNotWithinAPixel(largeDim, greenSquare.getHeight());
-
- assertNull(redSquare.getClipBounds());
- assertNull(greenSquare.getClipBounds());
- }
-
private static boolean isWithinAPixel(float expectedDim, int dim) {
return (Math.abs(dim - expectedDim) <= 1);
}
@@ -322,5 +271,114 @@
assertTrue("Expected dimension to not be within one pixel of "
+ expectedDim + ", but was " + dim, !isWithinAPixel(expectedDim, dim));
}
+
+ private class MyChangeBounds extends ChangeBounds {
+ private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
+ if (animator != null && mBoundsChangeListener != null) {
+ animator.addListener(mBoundsChangeListener);
+ Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+ Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ }
+ return animator;
+ }
+ }
+
+ private class ValidateBoundsListener implements ViewTreeObserver.OnDrawListener,
+ Animator.AnimatorListener {
+ final boolean mGrow;
+ final int mMin;
+ final int mMax;
+
+ final Point mRedDimensions = new Point(-1, -1);
+ final Point mGreenDimensions = new Point(-1, -1);
+
+ View mRedSquare;
+ View mGreenSquare;
+
+ boolean mDidChangeSize;
+
+ private ValidateBoundsListener(boolean grow) {
+ mGrow = grow;
+
+ Resources resources = mActivity.getResources();
+ mMin = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ SMALL_SQUARE_SIZE_DP, resources.getDisplayMetrics()));
+ mMax = (int) Math.ceil(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics()));
+ }
+
+ public void validateView(View view, Point dimensions) {
+ final String name = view.getTransitionName();
+ final boolean clipped = mChangeBounds.getResizeClip();
+ assertEquals(clipped, view.getClipBounds() != null);
+
+ final int width;
+ final int height;
+ if (clipped) {
+ width = view.getClipBounds().width();
+ height = view.getClipBounds().height();
+ } else {
+ width = view.getWidth();
+ height = view.getHeight();
+ }
+ validateDim(name, "width", dimensions.x, width);
+ validateDim(name, "height", dimensions.y, height);
+ dimensions.set(width, height);
+ }
+
+ private void validateDim(String name, String dimen, int lastDim, int newDim) {
+ if (lastDim != -1) {
+ if (mGrow) {
+ assertTrue(name + " new " + dimen + " " + newDim
+ + " is less than previous " + lastDim,
+ newDim >= lastDim);
+ } else {
+ assertTrue(name + " new " + dimen + " " + newDim
+ + " is more than previous " + lastDim,
+ newDim <= lastDim);
+ }
+ if (newDim != lastDim) {
+ mDidChangeSize = true;
+ }
+ }
+ assertTrue(name + " " + dimen + " " + newDim + " must be <= " + mMax,
+ newDim <= mMax);
+ assertTrue(name + " " + dimen + " " + newDim + " must be >= " + mMin,
+ newDim >= mMin);
+ }
+
+ @Override
+ public void onDraw() {
+ if (mRedSquare == null) {
+ mRedSquare = mActivity.findViewById(R.id.redSquare);
+ mGreenSquare = mActivity.findViewById(R.id.greenSquare);
+ }
+ validateView(mRedSquare, mRedDimensions);
+ validateView(mGreenSquare, mGreenDimensions);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mActivity.getWindow().getDecorView().getViewTreeObserver().addOnDrawListener(this);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mActivity.getWindow().getDecorView().getViewTreeObserver().removeOnDrawListener(this);
+ assertTrue(mDidChangeSize);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }
}
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index e42b33f..578591c 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -159,6 +159,9 @@
TvContentRating rating = TvContentRating.createRating("android.media.tv", "US_TVPG",
"US_TVPG_TV_MA", "US_TVPG_S", "US_TVPG_V");
values.put(Programs.COLUMN_CONTENT_RATING, rating.flattenToString());
+ values.put(Programs.COLUMN_REVIEW_RATING_STYLE,
+ RecordedPrograms.REVIEW_RATING_STYLE_STARS);
+ values.put(Programs.COLUMN_REVIEW_RATING, "4.5");
return values;
}
@@ -256,6 +259,9 @@
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 3);
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 2);
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 1);
+ values.put(RecordedPrograms.COLUMN_REVIEW_RATING_STYLE,
+ RecordedPrograms.REVIEW_RATING_STYLE_STARS);
+ values.put(RecordedPrograms.COLUMN_REVIEW_RATING, "4.5");
return values;
}
@@ -420,7 +426,6 @@
ContentValues baseValues = createDummyChannelValues(mInputId, false);
Uri channelUri = mContentResolver.insert(mChannelsUri, baseValues);
- final String COLUMN_SYSTEM_APPROVED = "system_approved";
// Test: insert
ContentValues values = new ContentValues(baseValues);
@@ -432,14 +437,6 @@
// Expected.
}
values = new ContentValues(baseValues);
- values.put(COLUMN_SYSTEM_APPROVED, 1);
- try {
- mContentResolver.insert(mChannelsUri, values);
- fail("'" + COLUMN_SYSTEM_APPROVED + "' should be read-only.");
- } catch (Exception e) {
- // Expected.
- }
- values = new ContentValues(baseValues);
values.put(Channels.COLUMN_LOCKED, 1);
try {
mContentResolver.insert(mChannelsUri, values);
@@ -458,14 +455,6 @@
// Expected.
}
values = new ContentValues(baseValues);
- values.put(COLUMN_SYSTEM_APPROVED, 1);
- try {
- mContentResolver.update(channelUri, values, null, null);
- fail("'" + COLUMN_SYSTEM_APPROVED + "' should be read-only.");
- } catch (Exception e) {
- // Expected.
- }
- values = new ContentValues(baseValues);
values.put(Channels.COLUMN_LOCKED, 1);
try {
mContentResolver.update(channelUri, values, null, null);
@@ -547,6 +536,8 @@
verifyStringColumn(cursor, expectedValues, Programs.COLUMN_THUMBNAIL_URI);
verifyBlobColumn(cursor, expectedValues, Programs.COLUMN_INTERNAL_PROVIDER_DATA);
verifyIntegerColumn(cursor, expectedValues, Programs.COLUMN_VERSION_NUMBER);
+ verifyStringColumn(cursor, expectedValues, Programs.COLUMN_REVIEW_RATING_STYLE);
+ verifyStringColumn(cursor, expectedValues, Programs.COLUMN_REVIEW_RATING);
}
}
@@ -708,6 +699,14 @@
Uri programUri = TvContract.buildPreviewProgramUri(programId);
verifyPreviewProgram(programUri, values, programId);
+ values.remove(PreviewPrograms.COLUMN_TYPE);
+ try {
+ mContentResolver.insert(previewProgramsUri, values);
+ fail("Type should be a required column.");
+ } catch (IllegalArgumentException e) {
+ // Expected.
+ }
+
// Test: update
values.put(PreviewPrograms.COLUMN_EPISODE_TITLE, "Sample title");
values.put(PreviewPrograms.COLUMN_SHORT_DESCRIPTION, "Short description");
@@ -735,6 +734,14 @@
Uri programUri = TvContract.buildWatchNextProgramUri(programId);
verifyWatchNextProgram(programUri, values, programId);
+ values.remove(WatchNextPrograms.COLUMN_TYPE);
+ try {
+ mContentResolver.insert(watchNextProgramsUri, values);
+ fail("Type should be a required column.");
+ } catch (IllegalArgumentException e) {
+ // Expected.
+ }
+
// Test: update
values.put(WatchNextPrograms.COLUMN_EPISODE_TITLE, "Sample title");
values.put(WatchNextPrograms.COLUMN_SHORT_DESCRIPTION, "Short description");
@@ -991,6 +998,8 @@
verifyIntegerColumn(cursor, expectedValues,
RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4);
verifyIntegerColumn(cursor, expectedValues, RecordedPrograms.COLUMN_VERSION_NUMBER);
+ verifyStringColumn(cursor, expectedValues, RecordedPrograms.COLUMN_REVIEW_RATING_STYLE);
+ verifyStringColumn(cursor, expectedValues, RecordedPrograms.COLUMN_REVIEW_RATING);
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
index e3d56ba..95c222c3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
@@ -20,14 +20,17 @@
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class AutofillHighlightTests extends ActivityTestBase {
@Test
public void testHighlightedFrameLayout() {
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 77ff8f2..d705c7e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -20,6 +20,7 @@
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
@@ -27,8 +28,10 @@
import android.uirendering.cts.testinfrastructure.CanvasClient;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class BitmapFilterTests extends ActivityTestBase {
private static final int WHITE_WEIGHT = 255 * 3;
private enum FilterEnum {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
index d9b8d7f..789d8d5 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
@@ -24,6 +24,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Handler;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
@@ -41,7 +42,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@MediumTest
+@LargeTest
@RunWith(AndroidJUnit4.class)
public class BitmapTests extends ActivityTestBase {
class BitmapView extends View {
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 d9eec30..16f98f6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -26,11 +26,13 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.util.DisplayMetrics;
import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Tests of state query-able from canvas at draw time.
@@ -39,6 +41,7 @@
* capability to test the hardware accelerated Canvas in the way that it is used by Views.
*/
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class CanvasStateTests extends ActivityTestBase {
@Test
public void testClipRectReturnValues() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
index bbc50df..5d875ab 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
@@ -22,17 +22,19 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
-import android.support.test.filters.LargeTest;
+import android.support.test.filters.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;
-@LargeTest // large while non-parameterized
-//@RunWith(Parameterized.class) // TODO: Reenable when CTS supports parameterized tests
+@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
@@ -85,12 +87,16 @@
0xFFC21A1A, 0xFFC93333, 0xFFD04D4D, 0xFFD66666, 0xFFBB0000 } },
};
- //@Parameterized.Parameters(name = "{0}")
+ @Parameterized.Parameters(name = "{0}")
public static List<XfermodeTest.Config> configs() {
return XfermodeTest.configs(MODES_AND_EXPECTED_COLORS);
}
- private XfermodeTest.Config mConfig;
+ private final XfermodeTest.Config mConfig;
+
+ public ColorFilterAlphaTest(XfermodeTest.Config config) {
+ mConfig = config;
+ }
private static final int[] BLOCK_COLORS = new int[] {
0x33808080,
@@ -127,12 +133,9 @@
@Test
public void test() {
- for (XfermodeTest.Config config : configs()) {
- mConfig = config;
- createTest()
- .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
- .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
- }
+ createTest()
+ .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
+ .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
index c5aa1b3..13c8e91 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
@@ -31,16 +31,19 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ColorSpaceTests extends ActivityTestBase {
private Bitmap mMask;
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 444af9f..304303a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.graphics.drawable.NinePatchDrawable;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.ExactComparer;
@@ -35,8 +36,10 @@
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ExactCanvasTests extends ActivityTestBase {
private final BitmapComparer mExactComparer = new ExactComparer();
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 2a2ec51..ea7403b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -22,6 +22,7 @@
import android.graphics.Paint;
import android.graphics.Typeface;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
@@ -29,8 +30,10 @@
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
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;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
index e808296..4b8b6b2 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
@@ -22,11 +22,14 @@
import android.graphics.Point;
import android.graphics.Shader;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class GradientTests extends ActivityTestBase {
@Test
public void testAlphaPreMultiplication() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
index 00b61e9..c62e134 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
@@ -28,6 +28,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.graphics.Bitmap;
@@ -41,11 +42,13 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class HardwareBitmapTests extends ActivityTestBase {
private Resources mRes;
@@ -82,7 +85,7 @@
HARDWARE_OPTIONS);
canvas.drawBitmap(hardwareBitmap, 0, 0, new Paint());
}, true).runWithVerifier(new GoldenImageVerifier(getActivity(),
- R.drawable.golden_headless_robot, new ExactComparer()));
+ R.drawable.golden_headless_robot, new MSSIMComparer(0.95)));
}
@Test
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 f952bc23..ee46601 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -18,7 +18,9 @@
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
@@ -28,8 +30,10 @@
import android.uirendering.cts.testinfrastructure.ViewInitializer;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class InfrastructureTests extends ActivityTestBase {
@Test
@@ -45,6 +49,7 @@
* by verifying that two paths that should render differently *do* render
* differently.
*/
+ @LargeTest
@Test
public void testRenderSpecIsolation() {
CanvasClient canvasClient = (canvas, width, height) -> {
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 f7661a5..ed0110a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -32,6 +32,7 @@
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.support.annotation.ColorInt;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
@@ -140,6 +141,7 @@
.runWithVerifier(new ColorVerifier(expectedColor));
}
+ @LargeTest
@Test
public void testLayerClear() {
ViewInitializer initializer = new ViewInitializer() {
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 c0323b6..3d1c10e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -18,14 +18,17 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class LayoutTests extends ActivityTestBase {
@Test
public void testSimpleRedLayout() {
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 6eaba8f..ae4fee1 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -24,7 +24,9 @@
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Typeface;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
@@ -38,10 +40,12 @@
import android.webkit.WebView;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class PathClippingTests extends ActivityTestBase {
// draw circle with hole in it, with stroked circle
static final CanvasClient sTorusDrawCanvasClient = (canvas, width, height) -> {
@@ -173,6 +177,7 @@
};
}
+ @LargeTest
@Test
public void testWebViewClipWithCircle() {
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
index 5abe831..2d5acaa 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
@@ -5,14 +5,17 @@
import android.graphics.Path;
import android.graphics.Typeface;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class PathTests extends ActivityTestBase {
private static final double REGULAR_THRESHOLD = 0.92;
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 c1e10d3..454eb2c0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
@@ -22,13 +22,16 @@
import android.graphics.Picture;
import android.graphics.Rect;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class PictureTest extends ActivityTestBase {
private static final Rect sRect = new Rect(0, 0, 40, 40);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java
index 44831bf..d9ec2b5 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java
@@ -25,16 +25,19 @@
import android.graphics.Point;
import android.graphics.Shader;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class Rgba16fTests extends ActivityTestBase {
@Test
public void testTransferFunctions() {
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 2c9df73..252874d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
@@ -27,14 +27,17 @@
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
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 org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ShaderTests extends ActivityTestBase {
@Test
public void testSinglePixelBitmapShader() {
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 e9b9bd4..e4f9809 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -18,14 +18,17 @@
import android.graphics.Color;
import android.graphics.Point;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.util.CompareUtils;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ShadowTests extends ActivityTestBase {
private class GrayScaleVerifier extends SamplePointVerifier {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
index 9aad23d..0b708d4 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
@@ -17,14 +17,17 @@
package android.uirendering.cts.testclasses;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ShapeTests extends ActivityTestBase {
@Test
public void testDashedOval() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
index 52b87cc..741c35c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
@@ -24,7 +24,9 @@
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -40,10 +42,12 @@
import org.junit.Assert;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
-@MediumTest
+@LargeTest
+@RunWith(AndroidJUnit4.class)
public class SurfaceViewTests extends ActivityTestBase {
static final CanvasCallback sGreenCanvasCallback =
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 c374dd7e..ff0e9a7 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -22,7 +22,9 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Shader;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -31,11 +33,13 @@
import android.uirendering.cts.testinfrastructure.ResourceModifier;
import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Test cases of all combination of resource modifications.
*/
-@MediumTest
+@LargeTest
+@RunWith(AndroidJUnit4.class)
public class SweepTests extends ActivityTestBase {
private final static DisplayModifier COLOR_FILTER_GRADIENT_MODIFIER = new DisplayModifier() {
private final Rect mBounds = new Rect(30, 30, 150, 150);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
index f220bfb..abbec36 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
@@ -27,6 +27,7 @@
import android.graphics.SurfaceTexture;
import android.support.annotation.ColorInt;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -42,10 +43,12 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class TextureViewTests extends ActivityTestBase {
private static SurfaceTexture sRedTexture;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
index 2a64ac4..ffb263d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
@@ -26,8 +26,10 @@
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class VectorDrawableTests extends ActivityTestBase {
@Test
public void testScaleDown() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
index d74dcb7..88aa265 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
@@ -17,6 +17,7 @@
package android.uirendering.cts.testclasses;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
@@ -25,8 +26,10 @@
import android.view.ViewAnimationUtils;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ViewAnimationUtilsTests extends ActivityTestBase {
@Test
public void testCreateCircularReveal() {
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 47f9f4d..d1f0ee5 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -7,6 +7,7 @@
import android.graphics.Path;
import android.graphics.Rect;
import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
@@ -18,6 +19,7 @@
import android.view.ViewOutlineProvider;
import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* This tests view clipping by modifying properties of blue_padded_layout, and validating
@@ -26,6 +28,7 @@
* Since the layout is blue on a white background, this is always done with a RectVerifier.
*/
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class ViewClippingTests extends ActivityTestBase {
static final Rect FULL_RECT = new Rect(0, 0, 90, 90);
static final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
index 04e1dfd..38a4d40 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
@@ -22,18 +22,20 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
-import android.support.test.filters.LargeTest;
+import android.support.test.filters.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;
-@LargeTest // large while non-parameterized
-//@RunWith(Parameterized.class) // TODO: Reenable when CTS supports parameterized tests
+@MediumTest
+@RunWith(Parameterized.class)
public class XfermodeTest extends ActivityTestBase {
/**
* There are 4 locations we care about in testing each filter:
@@ -124,12 +126,16 @@
BG_COLOR, DST_COLOR, SCREEN_COLOR, SRC_COLOR } },
};
- //@Parameterized.Parameters(name = "{0}")
+ @Parameterized.Parameters(name = "{0}")
public static List<Config> configs() {
return configs(MODES_AND_EXPECTED_COLORS);
}
- private Config mConfig;
+ private final Config mConfig;
+
+ public XfermodeTest(Config config) {
+ mConfig = config;
+ }
private CanvasClient mCanvasClient = new CanvasClient() {
final Paint mPaint = new Paint();
@@ -170,11 +176,8 @@
@Test
public void test() {
- for (XfermodeTest.Config config : configs()) {
- mConfig = config;
- createTest()
- .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
- .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
- }
+ createTest()
+ .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
+ .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
}
}
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 8afec2c..5f50e9c 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -331,6 +331,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity android:name="android.view.cts.DefaultFocusHighlightCtsActivity">
+ <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"
diff --git a/tests/tests/view/res/drawable/scrollbar_no_size.xml b/tests/tests/view/res/drawable/scrollbar_no_size.xml
deleted file mode 100644
index 88a59f0..0000000
--- a/tests/tests/view/res/drawable/scrollbar_no_size.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@android:color/white" />
-</shape>
diff --git a/tests/tests/view/res/drawable/scrollbar_thumb.xml b/tests/tests/view/res/drawable/scrollbar_thumb.xml
deleted file mode 100644
index d7612ac..0000000
--- a/tests/tests/view/res/drawable/scrollbar_thumb.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@android:color/white" />
- <size
- android:width="@dimen/scrollbar_thumb_width"
- android:height="@dimen/scrollbar_thumb_height"/>
-</shape>
diff --git a/tests/tests/view/res/drawable/scrollbar_track.xml b/tests/tests/view/res/drawable/scrollbar_track.xml
deleted file mode 100644
index a184569..0000000
--- a/tests/tests/view/res/drawable/scrollbar_track.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@android:color/white" />
- <size
- android:width="@dimen/scrollbar_track_width"
- android:height="@dimen/scrollbar_track_height"/>
-</shape>
diff --git a/tests/tests/view/res/layout/default_focus_highlight_layout.xml b/tests/tests/view/res/layout/default_focus_highlight_layout.xml
new file mode 100644
index 0000000..827de43
--- /dev/null
+++ b/tests/tests/view/res/layout/default_focus_highlight_layout.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <View
+ android:id="@+id/view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"/>
+
+ <ListView
+ android:id="@+id/listview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"/>
+
+ <EditText
+ android:id="@+id/edittext"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"
+ android:inputType="text"/>
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"/>
+
+ <LinearLayout
+ android:id="@+id/linearlayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ </LinearLayout>
+
+ <View
+ android:id="@+id/view_to_inflate"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:defaultFocusHighlightEnabled="false"
+ android:text="@string/id_ok"/>
+
+ <ListView
+ android:id="@+id/listview_to_inflate"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:defaultFocusHighlightEnabled="true"
+ android:text="@string/id_ok"/>
+
+ <EditText
+ android:id="@+id/edittext_to_inflate"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"
+ android:defaultFocusHighlightEnabled="true"
+ android:inputType="text"/>
+
+ <Button
+ android:id="@+id/button_to_inflate"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:defaultFocusHighlightEnabled="false"
+ android:text="@string/id_ok"/>
+
+ <LinearLayout
+ android:id="@+id/linearlayout_to_inflate"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:defaultFocusHighlightEnabled="false"
+ android:orientation="vertical">
+ </LinearLayout>
+
+</LinearLayout>
+
diff --git a/tests/tests/view/res/layout/focus_finder_layout.xml b/tests/tests/view/res/layout/focus_finder_layout.xml
index 610ffc8..1dea684 100644
--- a/tests/tests/view/res/layout/focus_finder_layout.xml
+++ b/tests/tests/view/res/layout/focus_finder_layout.xml
@@ -19,7 +19,7 @@
<TableLayout android:id="@+id/layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerInParent="true">
+ android:layout_alignParentTop="true">
<TableRow>
<android.view.cts.TestButton android:id="@+id/top_left_button"
android:layout_width="60dp"
@@ -41,5 +41,12 @@
android:text="BR" />
</TableRow>
</TableLayout>
+ <LinearLayout android:id="@+id/inflate_layout"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/layout">
+
+ </LinearLayout>
</RelativeLayout>
diff --git a/tests/tests/view/res/layout/focus_finder_sublayout.xml b/tests/tests/view/res/layout/focus_finder_sublayout.xml
new file mode 100644
index 0000000..c9a4c3b
--- /dev/null
+++ b/tests/tests/view/res/layout/focus_finder_sublayout.xml
@@ -0,0 +1,35 @@
+<?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:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <FrameLayout
+ android:focusableInTouchMode="true"
+ android:id="@+id/itembox"
+ android:layout_width="200px"
+ android:layout_height="200px">
+ <Button
+ android:id="@+id/itembutton"
+ android:focusableInTouchMode="true"
+ android:nextFocusForward="@id/itembox"
+ android:layout_gravity="bottom|right"
+ android:layout_marginRight="10px"
+ android:layout_marginBottom="10px"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index 3cfaafa..920da83 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -46,42 +46,6 @@
android:requiresFadingEdge="horizontal|vertical"
android:fadingEdgeLength="20px"/>
- <android.view.cts.MockView
- android:id="@+id/scroll_view_3"
- android:layout_width="100px"
- android:layout_height="200px"
- android:scrollbars="horizontal|vertical"
- android:scrollbarThumbVertical="@drawable/scrollbar_no_size"
- android:scrollbarThumbHorizontal="@drawable/scrollbar_no_size"/>
-
- <android.view.cts.MockView
- android:id="@+id/scroll_view_4"
- android:layout_width="100px"
- android:layout_height="200px"
- android:scrollbars="horizontal|vertical"
- android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
- android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"/>
-
- <android.view.cts.MockView
- android:id="@+id/scroll_view_5"
- android:layout_width="100px"
- android:layout_height="200px"
- android:scrollbars="horizontal|vertical"
- android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
- android:scrollbarTrackVertical="@drawable/scrollbar_track"
- android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"
- android:scrollbarTrackHorizontal="@drawable/scrollbar_track"/>
-
- <android.view.cts.MockView
- android:id="@+id/scroll_view_6"
- android:layout_width="100px"
- android:layout_height="200px"
- android:scrollbars="horizontal|vertical"
- android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
- android:scrollbarTrackVertical="@drawable/scrollbar_no_size"
- android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"
- android:scrollbarTrackHorizontal="@drawable/scrollbar_no_size"/>
-
<View
android:id="@+id/fit_windows"
android:fitsSystemWindows="true"
diff --git a/tests/tests/view/res/values/dimens.xml b/tests/tests/view/res/values/dimens.xml
index a1d66f9..59369a7 100644
--- a/tests/tests/view/res/values/dimens.xml
+++ b/tests/tests/view/res/values/dimens.xml
@@ -30,8 +30,4 @@
<dimen name="hover_target_margin">4dp</dimen>
<dimen name="hover_target_size">8dp</dimen>
<dimen name="hover_target_size_double">16dp</dimen>
- <dimen name="scrollbar_thumb_width">11dp</dimen>
- <dimen name="scrollbar_thumb_height">12dp</dimen>
- <dimen name="scrollbar_track_width">13dp</dimen>
- <dimen name="scrollbar_track_height">14dp</dimen>
</resources>
\ No newline at end of file
diff --git a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/tests/view/src/android/view/cts/DefaultFocusHighlightCtsActivity.java
similarity index 69%
rename from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
rename to tests/tests/view/src/android/view/cts/DefaultFocusHighlightCtsActivity.java
index d599eba..5211938 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/tests/view/src/android/view/cts/DefaultFocusHighlightCtsActivity.java
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-package com.android.cts.webkit.renderprocesscrash;
+package android.view.cts;
import android.app.Activity;
import android.os.Bundle;
-import android.webkit.WebView;
-public class RenderProcessCrashActivity extends Activity {
-
+/**
+ * A simple activity to test "Default Focus Highlight"
+ */
+public class DefaultFocusHighlightCtsActivity extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- WebView webView = new WebView(this);
- setContentView(webView);
- webView.loadUrl("chrome://kill");
+ setContentView(R.layout.default_focus_highlight_layout);
}
}
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 22fb6e0..8d56087 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -21,13 +21,16 @@
import static org.junit.Assert.assertTrue;
import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.FocusFinder;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.FrameLayout;
import org.junit.Before;
import org.junit.Rule;
@@ -340,4 +343,75 @@
View.FOCUS_BACKWARD);
assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
}
+
+ @Test
+ public void testDuplicateId() throws Throwable {
+ LayoutInflater inflater = mActivityRule.getActivity().getLayoutInflater();
+ mLayout = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.inflate_layout);
+ View[] buttons = new View[3];
+ View[] boxes = new View[3];
+ mActivityRule.runOnUiThread(() -> {
+ for (int i = 0; i < 3; ++i) {
+ View item = inflater.inflate(R.layout.focus_finder_sublayout, mLayout, false);
+ buttons[i] = item.findViewById(R.id.itembutton);
+ boxes[i] = item.findViewById(R.id.itembox);
+ mLayout.addView(item);
+ }
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ verifyNextFocus(buttons[0], View.FOCUS_FORWARD, boxes[0]);
+ verifyNextFocus(boxes[0], View.FOCUS_FORWARD, buttons[1]);
+ verifyNextFocus(buttons[1], View.FOCUS_FORWARD, boxes[1]);
+ verifyNextFocus(boxes[1], View.FOCUS_FORWARD, buttons[2]);
+ }
+
+ @Test
+ public void testBasicFocusOrder() {
+ // Sanity check to make sure sorter is behaving
+ FrameLayout layout = new FrameLayout(mLayout.getContext());
+ Button button1 = new Button(mLayout.getContext());
+ Button button2 = new Button(mLayout.getContext());
+ button1.setLeftTopRightBottom(0, 0, 10, 10);
+ button2.setLeftTopRightBottom(0, 0, 10, 10);
+ layout.addView(button1);
+ layout.addView(button2);
+ View[] views = new View[]{button2, button1};
+ // empty shouldn't crash or anything
+ FocusFinder.sort(views, 0, 0, layout, false);
+ // one view should work
+ FocusFinder.sort(views, 0, 1, layout, false);
+ assertEquals(button2, views[0]);
+ // exactly overlapping views should remain in original order
+ FocusFinder.sort(views, 0, 2, layout, false);
+ assertEquals(button2, views[0]);
+ assertEquals(button1, views[1]);
+ // make sure it will actually mutate input array.
+ button2.setLeftTopRightBottom(20, 0, 30, 10);
+ FocusFinder.sort(views, 0, 2, layout, false);
+ assertEquals(button1, views[0]);
+ assertEquals(button2, views[1]);
+
+ // While we don't want to test details, we should at least verify basic correctness
+ // like "left-to-right" ordering in well-behaved layouts
+ assertEquals(mLayout.findFocus(), mTopLeft);
+ verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+ verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+ verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
+
+ // Should still work intuitively even if some views are slightly shorter.
+ mBottomLeft.setBottom(mBottomLeft.getBottom() - 3);
+ mBottomLeft.offsetTopAndBottom(3);
+ verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+ verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+ verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
+
+ // RTL layout should work right-to-left
+ mActivityRule.getActivity().runOnUiThread(
+ () -> mLayout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+ verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+ verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
+ }
}
diff --git a/tests/tests/view/src/android/view/cts/MenuItemTest.java b/tests/tests/view/src/android/view/cts/MenuItemTest.java
index fc0ae0b..c9d362c 100644
--- a/tests/tests/view/src/android/view/cts/MenuItemTest.java
+++ b/tests/tests/view/src/android/view/cts/MenuItemTest.java
@@ -60,7 +60,7 @@
}
@Test
- public void testAccessThumbTint() {
+ public void testAccessIconTint() {
// Note that this test is not marked as @UiThreadTest. Updating MenuItem does not
// immediately update the displayed content, and even though the getters are expected
// to immediately return the just-set value, using instrumentation to wait for the
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java b/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java
index a6bc5fb..cb85712 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java
@@ -52,8 +52,9 @@
private static final int RECT_RIGHT = 200;
private static final int RECT_BOTTOM = 200;
+ private Canvas mCanvas;
+
private SurfaceHolder mHolder;
- private MockCanvas mCanvas;
private boolean mIsDraw;
private boolean mIsAttachedToWindow;
@@ -64,6 +65,7 @@
private boolean mIsOnWindowVisibilityChanged;
private boolean mIsDispatchDraw;
private boolean mIsSurfaceChanged;
+ private boolean mSurfaceCreatedCalled;
private int mWidthInOnMeasure;
private int mHeightInOnMeasure;
@@ -170,10 +172,12 @@
}
public void surfaceCreated(SurfaceHolder holder) {
+ mSurfaceCreatedCalled = true;
+
// Use mock canvas listening to the drawColor() calling.
- mCanvas = new MockCanvas(Bitmap.createBitmap( BITMAP_WIDTH,
- BITMAP_HEIGHT,
- Bitmap.Config.ARGB_8888));
+ mCanvas = new Canvas(Bitmap.createBitmap( BITMAP_WIDTH,
+ BITMAP_HEIGHT,
+ Bitmap.Config.ARGB_8888));
draw(mCanvas);
// Lock the surface, this returns a Canvas that can be used to render into.
@@ -186,6 +190,10 @@
mHolder.unlockCanvasAndPost(canvas);
}
+ boolean isSurfaceCreatedCalled() {
+ return mSurfaceCreatedCalled;
+ }
+
public void surfaceDestroyed(SurfaceHolder holder) {
}
@@ -229,44 +237,8 @@
return mIsDispatchDraw;
}
- public boolean isDrawColor() {
- if (mCanvas != null) {
- return mCanvas.isDrawColor();
- } else {
- return false;
- }
- }
-
public boolean isSurfaceChanged() {
return mIsSurfaceChanged;
}
-
- public void setDrawColor(boolean isDrawColor) {
- if (mCanvas != null) {
- mCanvas.setDrawColor(isDrawColor);
- }
- }
- }
-
- class MockCanvas extends Canvas {
- private boolean mIsDrawColor;
-
- public MockCanvas(Bitmap bitmap) {
- super(bitmap);
- }
-
- @Override
- public void drawColor(int color, Mode mode) {
- super.drawColor(color, mode);
- mIsDrawColor = true;
- }
-
- public boolean isDrawColor() {
- return mIsDrawColor;
- }
-
- public void setDrawColor(boolean isDrawColor) {
- this.mIsDrawColor = isDrawColor;
- }
}
}
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
index 277a094..5d90c73 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
@@ -79,7 +79,7 @@
assertTrue(mMockSurfaceView.isDraw());
assertTrue(mMockSurfaceView.isOnAttachedToWindow());
assertTrue(mMockSurfaceView.isDispatchDraw());
- assertTrue(mMockSurfaceView.isDrawColor());
+ assertTrue(mMockSurfaceView.isSurfaceCreatedCalled());
assertTrue(mMockSurfaceView.isSurfaceChanged());
assertTrue(mMockSurfaceView.isOnWindowVisibilityChanged());
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 17c6843..95b8491 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -208,6 +208,19 @@
mMockViewGroup.setVisibility(View.GONE);
parent.addKeyboardNavigationClusters(list, 0);
assertEquals(0, list.size());
+ list.clear();
+
+ // Nested clusters are ignored
+ TestClusterHier h = new TestClusterHier();
+ h.nestedGroup.setKeyboardNavigationCluster(true);
+ h.cluster2.setKeyboardNavigationCluster(false);
+ h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD);
+ assertTrue(list.contains(h.nestedGroup));
+ list.clear();
+ h.cluster2.setKeyboardNavigationCluster(true);
+ h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD);
+ assertFalse(list.contains(h.nestedGroup));
+ list.clear();
}
@UiThreadTest
@@ -1562,6 +1575,14 @@
h.c2view1.setVisibility(View.INVISIBLE);
h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
assertSame(h.c2view2, h.top.findFocus());
+
+ // Nested clusters should be ignored.
+ h = new TestClusterHier();
+ h.c1view1.setFocusedInCluster();
+ h.nestedGroup.setKeyboardNavigationCluster(true);
+ h.c2view2.setFocusedInCluster();
+ h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
+ assertSame(h.c2view2, h.top.findFocus());
}
@UiThreadTest
@@ -1781,6 +1802,7 @@
// can normal-navigate around once inside
h.top.addFocusables(views, View.FOCUS_DOWN);
assertTrue(views.contains(h.c1view1));
+ views.clear();
h.c1view1.requestFocus();
assertSame(h.c1view1, h.top.findFocus());
// focus loops within cluster (doesn't leave)
@@ -1791,6 +1813,17 @@
h.c2view2.requestFocus();
h.c1view1.requestFocus();
assertSame(h.c2view2, h.top.findFocus());
+
+ h = new TestClusterHier(false);
+ h.c1view1.requestFocus();
+ h.nestedGroup.setKeyboardNavigationCluster(true);
+ h.nestedGroup.setTouchscreenBlocksFocus(true);
+ // since cluster is nested, it should ignore its touchscreenBlocksFocus behavior.
+ h.c2view2.requestFocus();
+ assertSame(h.c2view2, h.top.findFocus());
+ h.top.addFocusables(views, View.FOCUS_DOWN);
+ assertTrue(views.contains(h.c2view2));
+ views.clear();
}
@UiThreadTest
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index ca39aab..2550915 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -3661,67 +3661,6 @@
}
@Test
- public void testScrollbarSize() {
- final int configScrollbarSize = ViewConfiguration.get(mActivity).getScaledScrollBarSize();
- final int customScrollbarSize = configScrollbarSize * 2;
-
- // No explicit scrollbarSize or custom drawables, ViewConfiguration applies.
- final MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
- assertEquals(configScrollbarSize, view.getScrollBarSize());
- assertEquals(configScrollbarSize, view.getVerticalScrollbarWidth());
- assertEquals(configScrollbarSize, view.getHorizontalScrollbarHeight());
-
- // No custom drawables, explicit scrollbarSize takes precedence.
- final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view_2);
- view2.setScrollBarSize(customScrollbarSize);
- assertEquals(customScrollbarSize, view2.getScrollBarSize());
- assertEquals(customScrollbarSize, view2.getVerticalScrollbarWidth());
- assertEquals(customScrollbarSize, view2.getHorizontalScrollbarHeight());
-
- // Custom drawables with no intrinsic size, ViewConfiguration applies.
- final MockView view3 = (MockView) mActivity.findViewById(R.id.scroll_view_3);
- assertEquals(configScrollbarSize, view3.getVerticalScrollbarWidth());
- assertEquals(configScrollbarSize, view3.getHorizontalScrollbarHeight());
- // Explicit scrollbarSize takes precedence.
- view3.setScrollBarSize(customScrollbarSize);
- assertEquals(view3.getScrollBarSize(), view3.getVerticalScrollbarWidth());
- assertEquals(view3.getScrollBarSize(), view3.getHorizontalScrollbarHeight());
-
- // Custom thumb drawables with intrinsic sizes define the scrollbars' dimensions.
- final MockView view4 = (MockView) mActivity.findViewById(R.id.scroll_view_4);
- final Resources res = mActivity.getResources();
- final int thumbWidth = res.getDimensionPixelOffset(R.dimen.scrollbar_thumb_width);
- final int thumbHeight = res.getDimensionPixelOffset(R.dimen.scrollbar_thumb_height);
- assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
- assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
- // Explicit scrollbarSize has no effect.
- view4.setScrollBarSize(customScrollbarSize);
- assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
- assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
-
- // Custom thumb and track drawables with intrinsic sizes. Track size take precedence.
- final MockView view5 = (MockView) mActivity.findViewById(R.id.scroll_view_5);
- final int trackWidth = res.getDimensionPixelOffset(R.dimen.scrollbar_track_width);
- final int trackHeight = res.getDimensionPixelOffset(R.dimen.scrollbar_track_height);
- assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
- assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
- // Explicit scrollbarSize has no effect.
- view5.setScrollBarSize(customScrollbarSize);
- assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
- assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
-
- // Custom thumb and track, track with no intrinsic size, ViewConfiguration applies
- // regardless of the thumb drawable dimensions.
- final MockView view6 = (MockView) mActivity.findViewById(R.id.scroll_view_6);
- assertEquals(configScrollbarSize, view6.getVerticalScrollbarWidth());
- assertEquals(configScrollbarSize, view6.getHorizontalScrollbarHeight());
- // Explicit scrollbarSize takes precedence.
- view6.setScrollBarSize(customScrollbarSize);
- assertEquals(customScrollbarSize, view6.getVerticalScrollbarWidth());
- assertEquals(customScrollbarSize, view6.getHorizontalScrollbarHeight());
- }
-
- @Test
public void testOnStartAndFinishTemporaryDetach() throws Throwable {
final AtomicBoolean exitedDispatchStartTemporaryDetach = new AtomicBoolean(false);
final AtomicBoolean exitedDispatchFinishTemporaryDetach = new AtomicBoolean(false);
diff --git a/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java b/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
new file mode 100644
index 0000000..5e362cf
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_DefaultFocusHighlightTest {
+
+ @Rule
+ public ActivityTestRule<DefaultFocusHighlightCtsActivity> mActivityRule =
+ new ActivityTestRule<>(DefaultFocusHighlightCtsActivity.class);
+
+ @UiThreadTest
+ @Test
+ public void testSettersAndGetters() {
+ Activity activity = mActivityRule.getActivity();
+
+ View view = activity.findViewById(R.id.view);
+ ListView listView = (ListView) activity.findViewById(R.id.listview);
+ EditText editText = (EditText) activity.findViewById(R.id.edittext);
+ Button button = (Button) activity.findViewById(R.id.button);
+ LinearLayout linearLayout = (LinearLayout) activity.findViewById(R.id.linearlayout);
+
+ assertTrue(view.getDefaultFocusHighlightEnabled());
+ assertFalse(listView.getDefaultFocusHighlightEnabled());
+ assertFalse(editText.getDefaultFocusHighlightEnabled());
+ assertTrue(button.getDefaultFocusHighlightEnabled());
+ assertTrue(linearLayout.getDefaultFocusHighlightEnabled());
+
+ view.setDefaultFocusHighlightEnabled(false);
+ listView.setDefaultFocusHighlightEnabled(true);
+ editText.setDefaultFocusHighlightEnabled(true);
+ button.setDefaultFocusHighlightEnabled(false);
+ linearLayout.setDefaultFocusHighlightEnabled(false);
+
+ assertFalse(view.getDefaultFocusHighlightEnabled());
+ assertTrue(listView.getDefaultFocusHighlightEnabled());
+ assertTrue(editText.getDefaultFocusHighlightEnabled());
+ assertFalse(button.getDefaultFocusHighlightEnabled());
+ assertFalse(linearLayout.getDefaultFocusHighlightEnabled());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testInflating() {
+ Activity activity = mActivityRule.getActivity();
+
+ View view = activity.findViewById(R.id.view_to_inflate);
+ ListView listView = (ListView) activity.findViewById(R.id.listview_to_inflate);
+ EditText editText = (EditText) activity.findViewById(R.id.edittext_to_inflate);
+ Button button = (Button) activity.findViewById(R.id.button_to_inflate);
+ LinearLayout linearLayout = (LinearLayout) activity.findViewById(
+ R.id.linearlayout_to_inflate);
+
+ assertFalse(view.getDefaultFocusHighlightEnabled());
+ assertTrue(listView.getDefaultFocusHighlightEnabled());
+ assertTrue(editText.getDefaultFocusHighlightEnabled());
+ assertFalse(button.getDefaultFocusHighlightEnabled());
+ assertFalse(linearLayout.getDefaultFocusHighlightEnabled());
+ }
+}
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
index 3d9f66b..60ef12e 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
@@ -36,7 +36,7 @@
* Observed that first few frames have errors with SurfaceView placement, so we skip for now.
* b/29603849 tracking that issue.
*/
- private static final int NUM_FIRST_FRAMES_SKIPPED = 8;
+ private static final int NUM_FIRST_FRAMES_SKIPPED = 25;
// If no channel is greater than this value, pixel will be considered 'blackish'.
private static final short PIXEL_CHANNEL_THRESHOLD = 4;
@@ -78,6 +78,7 @@
synchronized (mResultLock) {
if (numSkipped < NUM_FIRST_FRAMES_SKIPPED) {
numSkipped++;
+ Log.d(TAG, "skipped fram nr " + numSkipped + ", success = " + success);
} else {
if (success) {
mResultSuccessFrames++;
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
index b16d473..a840116 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
@@ -17,7 +17,6 @@
package android.view.textclassifier.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import android.os.LocaleList;
@@ -25,21 +24,12 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassificationResult;
import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLanguage;
-import android.view.textclassifier.TextSelection;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-import java.util.Locale;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
@@ -53,78 +43,23 @@
public void setup() {
mTcm = InstrumentationRegistry.getTargetContext()
.getSystemService(TextClassificationManager.class);
- mTcm.setTextClassifier(null);
+ mTcm.setTextClassifier(null); // Resets the classifier.
mClassifier = mTcm.getTextClassifier();
}
@Test
- public void testSmartSelection() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String selected = "droid";
- String suggested = "droid@android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
-
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
+ public void testSmartSelectionDoesNotThrowException() {
+ mClassifier.suggestSelection("text", 2, 3, LOCALES);
}
@Test
- public void testSmartSelection_url() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit http://www.android.com for more information";
- String selected = "http";
- String suggested = "http://www.android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
-
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
+ public void testTextClassificationResultDoesNotThrowException() {
+ mClassifier.getTextClassificationResult("text", 2, 3, LOCALES);
}
@Test
- public void testTextClassificationResult() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String classifiedText = "droid@android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES),
- isTextClassificationResult(classifiedText, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testTextClassificationResult_url() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit http://www.android.com for more information";
- String classifiedText = "http://www.android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES),
- isTextClassificationResult(classifiedText, TextClassifier.TYPE_URL));
- }
-
- @Test
- public void testLanguageDetection() {
- if (isTextClassifierDisabled()) return;
-
- String text = "This is english text";
- assertThat(mTcm.detectLanguages(text), isDetectedLanguage("en"));
-
- text = "Das ist deutscher text";
- assertThat(mTcm.detectLanguages(text), isDetectedLanguage("de"));
-
- text = "これは日本語テキストです";
- assertThat(mTcm.detectLanguages(text), isDetectedLanguage("ja"));
+ public void testLanguageDetectionDoesNotThrowException() {
+ mTcm.detectLanguages("text");
}
@Test
@@ -133,80 +68,4 @@
mTcm.setTextClassifier(classifier);
assertEquals(classifier, mTcm.getTextClassifier());
}
-
- private boolean isTextClassifierDisabled() {
- return mClassifier == TextClassifier.NO_OP;
- }
-
- private static Matcher<TextSelection> isTextSelection(
- final int startIndex, final int endIndex, final String type) {
- return new BaseMatcher<TextSelection>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextSelection) {
- TextSelection selection = (TextSelection) o;
- return startIndex == selection.getSelectionStartIndex()
- && endIndex == selection.getSelectionEndIndex()
- && selection.getEntityCount() > 0
- && type.equals(selection.getEntity(0));
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendValue(
- String.format("%d, %d, %s", startIndex, endIndex, type));
- }
- };
- }
-
- private static Matcher<TextClassificationResult> isTextClassificationResult(
- final String text, final String type) {
- return new BaseMatcher<TextClassificationResult>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextClassificationResult) {
- TextClassificationResult result = (TextClassificationResult) o;
- return text.equals(result.getText())
- && result.getEntityCount() > 0
- && type.equals(result.getEntity(0));
- // TODO: Include other properties.
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("text=").appendValue(text)
- .appendText(", type=").appendValue(type);
- }
- };
- }
-
- private static Matcher<List<TextLanguage>> isDetectedLanguage(final String language) {
- return new BaseMatcher<List<TextLanguage>>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof List) {
- List languages = (List) o;
- if (!languages.isEmpty()) {
- Object o1 = languages.get(0);
- if (o1 instanceof TextLanguage) {
- TextLanguage lang = (TextLanguage) o1;
- return lang.getLanguageCount() > 0
- && new Locale(language).getLanguage()
- .equals(lang.getLanguage(0).getLanguage());
- }
- }
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendValue(String.format("%s", language));
- }
- };
- }
}
diff --git a/tests/tests/webkit/AndroidManifest.xml b/tests/tests/webkit/AndroidManifest.xml
index 44df7c4..83775df 100644
--- a/tests/tests/webkit/AndroidManifest.xml
+++ b/tests/tests/webkit/AndroidManifest.xml
@@ -56,6 +56,8 @@
</intent-filter>
</activity>
+ <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" />
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/widget/res/layout/textview_imeoptions.xml b/tests/tests/widget/res/layout/textview_imeoptions.xml
new file mode 100644
index 0000000..82b1d26
--- /dev/null
+++ b/tests/tests/widget/res/layout/textview_imeoptions.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <!-- Test EditorInfo.IME_NULL -->
+ <TextView
+ android:id="@+id/textview_imeoption_normal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="normal" />
+
+ <!-- Test EditorInfo.IME_ACTION_* -->
+ <TextView
+ android:id="@+id/textview_imeoption_action_unspecified"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionUnspecified" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_none"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionNone" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_go"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionGo" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_search"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionSearch" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_send"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionSend" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_next"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionNext" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_done"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionDone" />
+ <TextView
+ android:id="@+id/textview_imeoption_action_previous"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionPrevious" />
+
+ <!-- Test EditorInfo.IME_FLAG_* -->
+ <TextView
+ android:id="@+id/textview_imeoption_no_personalized_learning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoPersonalizedLearning" />
+ <TextView
+ android:id="@+id/textview_imeoption_no_fullscreen"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoFullscreen" />
+ <TextView
+ android:id="@+id/textview_imeoption_navigation_previous"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNavigatePrevious" />
+ <TextView
+ android:id="@+id/textview_imeoption_navigation_next"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNavigateNext" />
+ <TextView
+ android:id="@+id/textview_imeoption_no_extract_ui"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoExtractUi" />
+ <TextView
+ android:id="@+id/textview_imeoption_no_accessory_action"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoAccessoryAction" />
+ <TextView
+ android:id="@+id/textview_imeoption_no_enter_action"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoEnterAction" />
+ <TextView
+ android:id="@+id/textview_imeoption_force_ascii"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="flagForceAscii" />
+
+ <!-- test an action with multiple flags -->
+ <TextView
+ android:id="@+id/textview_imeoption_action_go_nagivate_next_no_extract_ui_force_ascii"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionGo|flagNavigateNext|flagNoExtractUi|flagForceAscii" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index 70fbd73..93f4846 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -282,6 +282,13 @@
android:autoSizeStepGranularity="1px" />
<TextView
+ android:id="@+id/textview_autosize_basic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_view_hello"
+ android:autoSizeTextType="uniform" />
+
+ <TextView
android:id="@+id/textview_fontresource_fontfamily"
android:text="@string/text_view_hello"
android:layout_width="wrap_content"
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index 4e33156..b2fd35c 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -362,6 +362,11 @@
assertTrue(mAdapterView.isFocusable());
assertTrue(mAdapterView.isFocusableInTouchMode());
+ // FOCUSABLE_AUTO should also work with children added (AbsListView is clickable)
+ mAdapterView.setFocusable(View.FOCUSABLE_AUTO);
+ assertTrue(mAdapterView.isFocusable());
+ assertTrue(mAdapterView.isFocusableInTouchMode());
+
mAdapterView.setFocusable(false);
assertFalse(mAdapterView.isFocusable());
assertFalse(mAdapterView.isFocusableInTouchMode());
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index 2b55ed5..5476b22 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -510,7 +510,6 @@
Drawable backgroundDrawable = new ColorDrawable(0xFF0000FF);
mockImageView.setBackgroundDrawable(backgroundDrawable);
- assertFalse(mockImageView.verifyDrawable(null));
assertFalse(mockImageView.verifyDrawable(new ColorDrawable(0xFF00FF00)));
assertTrue(mockImageView.verifyDrawable(drawable));
assertTrue(mockImageView.verifyDrawable(backgroundDrawable));
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 209f689..de6df87 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -1445,6 +1445,12 @@
mPopupWindow = createPopupWindow(
mActivity.getLayoutInflater().inflate(R.layout.popup_window, null));
+ // This ensures that mPopupWindow is flipped vertically when anchored to one of the views
+ // at the bottom of the window (R.id.anchor_lower_*).
+ // This way the bottom edge of subPopup's anchor is aligned with the bottom edge of the
+ // window as well, which makes it possible to predict whether subPopup is going to flipped.
+ mPopupWindow.setOverlapAnchor(true);
+
final PopupWindow subPopup =
createPopupWindow(createPopupContent(CONTENT_SIZE_DP, CONTENT_SIZE_DP));
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index 4ced4fb..5a68273 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -514,26 +514,22 @@
public void testVerifyDrawable() {
MockProgressBar mockProgressBar =
(MockProgressBar) mActivity.findViewById(R.id.progress_custom);
- assertTrue(mockProgressBar.verifyDrawable(null));
Drawable d1 = mActivity.getDrawable(R.drawable.blue);
Drawable d2 = mActivity.getDrawable(R.drawable.red);
Drawable d3 = mActivity.getDrawable(R.drawable.yellow);
mockProgressBar.setBackgroundDrawable(d1);
- assertTrue(mockProgressBar.verifyDrawable(null));
assertTrue(mockProgressBar.verifyDrawable(d1));
assertFalse(mockProgressBar.verifyDrawable(d2));
assertFalse(mockProgressBar.verifyDrawable(d3));
mockProgressBar.setIndeterminateDrawable(d2);
- assertTrue(mockProgressBar.verifyDrawable(null));
assertTrue(mockProgressBar.verifyDrawable(d1));
assertTrue(mockProgressBar.verifyDrawable(d2));
assertFalse(mockProgressBar.verifyDrawable(d3));
mockProgressBar.setProgressDrawable(d3);
- assertFalse(mockProgressBar.verifyDrawable(null));
assertTrue(mockProgressBar.verifyDrawable(d1));
assertTrue(mockProgressBar.verifyDrawable(d2));
assertTrue(mockProgressBar.verifyDrawable(d3));
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 968b6e3..a7cde1a 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -42,6 +42,9 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
@@ -63,6 +66,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.fonts.FontVariationAxis;
+import android.icu.lang.UCharacter;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -157,6 +161,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Locale;
@@ -410,6 +415,108 @@
assertEquals(-1, mTextView.getGravity());
}
+ @Retention(SOURCE)
+ @IntDef({EditorInfo.IME_ACTION_UNSPECIFIED, EditorInfo.IME_ACTION_NONE,
+ EditorInfo.IME_ACTION_GO, EditorInfo.IME_ACTION_SEARCH, EditorInfo.IME_ACTION_SEND,
+ EditorInfo.IME_ACTION_NEXT, EditorInfo.IME_ACTION_DONE, EditorInfo.IME_ACTION_PREVIOUS})
+ private @interface ImeOptionAction {}
+
+ @Retention(SOURCE)
+ @IntDef(flag = true,
+ value = {EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING,
+ EditorInfo.IME_FLAG_NO_FULLSCREEN, EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT, EditorInfo.IME_FLAG_NO_EXTRACT_UI,
+ EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION, EditorInfo.IME_FLAG_NO_ENTER_ACTION,
+ EditorInfo.IME_FLAG_FORCE_ASCII})
+ private @interface ImeOptionFlags {}
+
+ private static void assertImeOptions(TextView textView,
+ @ImeOptionAction int expectedImeOptionAction,
+ @ImeOptionFlags int expectedImeOptionFlags) {
+ final int actualAction = textView.getImeOptions() & EditorInfo.IME_MASK_ACTION;
+ final int actualFlags = textView.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
+ assertEquals(expectedImeOptionAction, actualAction);
+ assertEquals(expectedImeOptionFlags, actualFlags);
+ }
+
+ @UiThreadTest
+ @Test
+ public void testImeOptions() {
+ mActivity.setContentView(R.layout.textview_imeoptions);
+
+ // Test "normal" to be a synonym EditorInfo.IME_NULL
+ assertEquals(EditorInfo.IME_NULL,
+ mActivity.<TextView>findViewById(R.id.textview_imeoption_normal).getImeOptions());
+
+ // Test EditorInfo.IME_ACTION_*
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_unspecified),
+ EditorInfo.IME_ACTION_UNSPECIFIED, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_none),
+ EditorInfo.IME_ACTION_NONE, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_go),
+ EditorInfo.IME_ACTION_GO, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_search),
+ EditorInfo.IME_ACTION_SEARCH, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_send),
+ EditorInfo.IME_ACTION_SEND, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_next),
+ EditorInfo.IME_ACTION_NEXT, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_done),
+ EditorInfo.IME_ACTION_DONE, 0);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_action_previous),
+ EditorInfo.IME_ACTION_PREVIOUS, 0);
+
+ // Test EditorInfo.IME_FLAG_*
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_no_personalized_learning),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_no_fullscreen),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NO_FULLSCREEN);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_navigation_previous),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_navigation_next),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_no_extract_ui),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NO_EXTRACT_UI);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_no_accessory_action),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_no_enter_action),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+ assertImeOptions(
+ mActivity.findViewById(R.id.textview_imeoption_force_ascii),
+ EditorInfo.IME_ACTION_UNSPECIFIED,
+ EditorInfo.IME_FLAG_FORCE_ASCII);
+
+ // test action + multiple flags
+ assertImeOptions(
+ mActivity.findViewById(
+ R.id.textview_imeoption_action_go_nagivate_next_no_extract_ui_force_ascii),
+ EditorInfo.IME_ACTION_GO,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI
+ | EditorInfo.IME_FLAG_FORCE_ASCII);
+ }
+
@Test
public void testAccessAutoLinkMask() throws Throwable {
mTextView = findTextView(R.id.textview_text);
@@ -3369,9 +3476,22 @@
// The default variation settings should be null.
assertNull(mTextView.getFontVariationSettings());
- final String[] nonEffectiveSettings = {
+ final String[] invalidFormatSettings = {
"invalid syntax",
"'aaa' 1.0", // tag is not 4 ascii chars
+ };
+ for (String settings : invalidFormatSettings) {
+ try {
+ mTextView.setFontVariationSettings(settings);
+ fail();
+ } catch (FontVariationAxis.InvalidFormatException e) {
+ // pass.
+ }
+ assertNull("Must not change settings for " + settings,
+ mTextView.getFontVariationSettings());
+ }
+
+ final String[] nonEffectiveSettings = {
"'bbbb' 1.0", // unsupported tag
"' ' 1.0", // unsupported tag
"'AAAA' 0.7", // unsupported tag (case sensitive)
@@ -4531,7 +4651,8 @@
assertEquals(InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_DECIMAL
| InputType.TYPE_NUMBER_FLAG_SIGNED, mTextView.getInputType());
- assertSame(mTextView.getKeyListener(), DigitsKeyListener.getInstance(true, true));
+ assertSame(mTextView.getKeyListener(),
+ DigitsKeyListener.getInstance(null, true, true));
mTextView.setInputType(InputType.TYPE_CLASS_PHONE);
assertEquals(InputType.TYPE_CLASS_PHONE, mTextView.getInputType());
@@ -4747,6 +4868,59 @@
@UiThreadTest
@Test
+ public void testSetImeHintLocalesChangesInputType() {
+ final TextView textView = new TextView(mActivity);
+ textView.setText("", BufferType.EDITABLE);
+
+ textView.setInputType(InputType.TYPE_CLASS_NUMBER);
+ assertEquals(InputType.TYPE_CLASS_NUMBER, textView.getInputType());
+
+ final LocaleList localeList = LocaleList.forLanguageTags("fa-IR");
+ textView.setImeHintLocales(localeList);
+ final int textType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ // Setting IME hint locales to Persian must change the input type to a full text IME,
+ // since the typical number input IME may not have localized digits.
+ assertEquals(textType, textView.getInputType());
+
+ // Changing the input type to datetime should keep the full text IME, since the IME hint
+ // is still set to Persian, which needs advanced input.
+ final int dateType = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+ textView.setInputType(dateType);
+ assertEquals(textType, textView.getInputType());
+
+ // Changing the input type to number password should keep the full text IME, since the IME
+ // hint is still set to Persian, which needs advanced input. But it also needs to set the
+ // text password flag.
+ final int numberPasswordType = InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
+ final int textPasswordType = InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+ textView.setInputType(numberPasswordType);
+ assertEquals(textPasswordType, textView.getInputType());
+
+ // Setting the IME hint locales to null should reset the type to number password, since we
+ // no longer need internationalized input.
+ textView.setImeHintLocales(null);
+ assertEquals(numberPasswordType, textView.getInputType());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testSetImeHintLocalesDoesntLoseInputType() {
+ final TextView textView = new TextView(mActivity);
+ textView.setText("", BufferType.EDITABLE);
+ final int inputType = InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+ | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
+ | InputType.TYPE_TEXT_FLAG_MULTI_LINE
+ | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
+ textView.setInputType(inputType);
+ textView.setImeHintLocales(new LocaleList(Locale.US));
+ assertEquals(inputType, textView.getInputType());
+ }
+
+ @UiThreadTest
+ @Test
public void testSetExtractedText() {
mTextView = findTextView(R.id.textview_text);
assertEquals(mActivity.getResources().getString(R.string.text_view_hello),
@@ -5391,28 +5565,75 @@
@UiThreadTest
@Test
- public void testAllCapsLocalization() {
- String testString = "abcdefghijklmnopqrstuvwxyz";
+ public void testAllCaps_Localization() {
+ final String testString = "abcdefghijklmnopqrstuvwxyz i\u0307\u0301 άέήίΐόύΰώάυ ή";
- // The capitalized characters of "i" on Turkish and Azerbaijani are different from English.
- Locale[] testLocales = {
- new Locale("az", "AZ"),
- new Locale("tr", "TR"),
- new Locale("en", "US"),
+ // Capital "i" in Turkish and Azerbaijani is different from English, Lithuanian has special
+ // rules for uppercasing dotted i with accents, and Greek has complex capitalization rules.
+ final Locale[] testLocales = {
+ new Locale("az", "AZ"), // Azerbaijani
+ new Locale("tr", "TR"), // Turkish
+ new Locale("lt", "LT"), // Lithuanian
+ new Locale("el", "GR"), // Greek
+ Locale.US,
};
- TextView tv = new TextView(mActivity);
+ final TextView tv = new TextView(mActivity);
tv.setAllCaps(true);
for (Locale locale: testLocales) {
tv.setTextLocale(locale);
assertEquals("Locale: " + locale.getDisplayName(),
- testString.toUpperCase(locale),
+ UCharacter.toUpperCase(locale, testString),
tv.getTransformationMethod().getTransformation(testString, tv).toString());
}
}
@UiThreadTest
@Test
+ public void testAllCaps_SpansArePreserved() {
+ final Locale greek = new Locale("el", "GR");
+ final String lowerString = "ι\u0301ριδα"; // ίριδα with first letter decomposed
+ final String upperString = "ΙΡΙΔΑ"; // uppercased
+ // expected lowercase to uppercase index map
+ final int[] indexMap = {0, 1, 1, 2, 3, 4, 5};
+ final int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
+
+ final TextView tv = new TextView(mActivity);
+ tv.setTextLocale(greek);
+ tv.setAllCaps(true);
+
+ final Spannable source = new SpannableString(lowerString);
+ source.setSpan(new Object(), 0, 1, flags);
+ source.setSpan(new Object(), 1, 2, flags);
+ source.setSpan(new Object(), 2, 3, flags);
+ source.setSpan(new Object(), 3, 4, flags);
+ source.setSpan(new Object(), 4, 5, flags);
+ source.setSpan(new Object(), 5, 6, flags);
+ source.setSpan(new Object(), 0, 2, flags);
+ source.setSpan(new Object(), 1, 3, flags);
+ source.setSpan(new Object(), 2, 4, flags);
+ source.setSpan(new Object(), 0, 6, flags);
+ final Object[] sourceSpans = source.getSpans(0, source.length(), Object.class);
+
+ final CharSequence transformed =
+ tv.getTransformationMethod().getTransformation(source, tv);
+ assertTrue(transformed instanceof Spanned);
+ final Spanned result = (Spanned) transformed;
+
+ assertEquals(upperString, transformed.toString());
+ final Object[] resultSpans = result.getSpans(0, result.length(), Object.class);
+ assertEquals(sourceSpans.length, resultSpans.length);
+ for (int i = 0; i < sourceSpans.length; i++) {
+ assertSame(sourceSpans[i], resultSpans[i]);
+ final Object span = sourceSpans[i];
+ assertEquals(indexMap[source.getSpanStart(span)], result.getSpanStart(span));
+ assertEquals(indexMap[source.getSpanEnd(span)], result.getSpanEnd(span));
+ assertEquals(source.getSpanFlags(span), result.getSpanFlags(span));
+ }
+ }
+
+ @UiThreadTest
+ @Test
public void testTextAlignmentDefault() {
TextView tv = new TextView(mActivity);
assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
@@ -6386,6 +6607,7 @@
final TextUtils.TruncateAt newEllipsizeValue = TextUtils.TruncateAt.END;
mActivityRule.runOnUiThread(() ->
textView.setEllipsize(newEllipsizeValue));
+ mInstrumentation.waitForIdleSync();
assertEquals(newEllipsizeValue, textView.getEllipsize());
assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_NONE, textView.getAutoSizeTextType());
assertEquals(-1, textView.getAutoSizeMinTextSize());
@@ -6395,6 +6617,7 @@
mActivityRule.runOnUiThread(() ->
textView.setAutoSizeTextTypeWithDefaults(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM));
+ mInstrumentation.waitForIdleSync();
assertEquals(newEllipsizeValue, textView.getEllipsize());
assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM, textView.getAutoSizeTextType());
// The auto-size defaults have been used.
@@ -6566,19 +6789,17 @@
public void testAutoSizeCallers_setHorizontallyScrolling() throws Throwable {
final TextView autoSizeTextView = prepareAndRetrieveAutoSizeTestData(
R.id.textview_autosize_uniform, false);
+ // Verify that we do not have horizontal scrolling turned on.
+ assertTrue(!autoSizeTextView.getHorizontallyScrolling());
+
final float initialTextSize = autoSizeTextView.getTextSize();
- mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(
- !autoSizeTextView.getHorizontallyScrolling()));
+ mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(true));
mInstrumentation.waitForIdleSync();
- final float changedTextSize = autoSizeTextView.getTextSize();
+ assertTrue(autoSizeTextView.getTextSize() > initialTextSize);
- assertTrue(changedTextSize < initialTextSize);
-
- mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(
- autoSizeTextView.getHorizontallyScrolling()));
+ mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(false));
mInstrumentation.waitForIdleSync();
-
- assertEquals(changedTextSize, autoSizeTextView.getTextSize(), 0f);
+ assertEquals(initialTextSize, autoSizeTextView.getTextSize(), 0f);
}
@Test
@@ -6712,6 +6933,19 @@
}
@Test
+ public void testAutoSizeCallers_setHeightForOneLineText() throws Throwable {
+ final TextView autoSizeTextView = (TextView) mActivity.findViewById(
+ R.id.textview_autosize_basic);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM, autoSizeTextView.getAutoSizeTextType());
+ final float initialTextSize = autoSizeTextView.getTextSize();
+ mActivityRule.runOnUiThread(() -> autoSizeTextView.setHeight(
+ autoSizeTextView.getHeight() * 3));
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(autoSizeTextView.getTextSize() > initialTextSize);
+ }
+
+ @Test
public void testAutoSizeUniform_obtainStyledAttributes() {
DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
TextView autoSizeTextViewUniform = (TextView) mActivity.findViewById(
@@ -7269,8 +7503,8 @@
}
private void calculatePositions() {
- int xStart = (int) mParent.getLayout().getPrimaryHorizontal(mStartCharPos, true, true);
- int xEnd = (int) mParent.getLayout().getPrimaryHorizontal(mEndCharPos, true, true);
+ int xStart = (int) mParent.getLayout().getPrimaryHorizontal(mStartCharPos, true);
+ int xEnd = (int) mParent.getLayout().getPrimaryHorizontal(mEndCharPos, true);
int line = mParent.getLayout().getLineForOffset(mEndCharPos);
int yTop = mParent.getLayout().getLineTop(line);
int yBottom = mParent.getLayout().getLineBottom(line);
@@ -7410,8 +7644,8 @@
*/
private static Point getCenterPositionOfTextAt(
TextView textView, int startIndex, int endIndex) {
- int xStart = (int) textView.getLayout().getPrimaryHorizontal(startIndex, true, true);
- int xEnd = (int) textView.getLayout().getPrimaryHorizontal(endIndex, true, true);
+ int xStart = (int) textView.getLayout().getPrimaryHorizontal(startIndex, true);
+ int xEnd = (int) textView.getLayout().getPrimaryHorizontal(endIndex, true);
int line = textView.getLayout().getLineForOffset(endIndex);
int yTop = textView.getLayout().getLineTop(line);
int yBottom = textView.getLayout().getLineBottom(line);
diff --git a/tools/cts-tradefed/res/config/cts-dev.xml b/tools/cts-tradefed/res/config/cts-dev.xml
index 97c3cdd..4ebda1b 100644
--- a/tools/cts-tradefed/res/config/cts-dev.xml
+++ b/tools/cts-tradefed/res/config/cts-dev.xml
@@ -20,6 +20,7 @@
<option name="log-level" value="verbose" />
<option name="skip-preconditions" value="true" />
<option name="skip-device-info" value="true" />
+ <option name="result-reporter:compress-logs" value="false" />
<option name="plan" value="cts-dev" />
<option name="compatibility:skip-all-system-status-check" value="true" />
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 4c0d1af..f694daa 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -175,15 +175,16 @@
<!-- b/31803630 -->
<option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
- <!-- b/36812770 -->
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAccelerometerHardwareBufferNormal" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testGyroscopeHardwareBufferNormal" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testMagneticFieldHardwareBufferNormal" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAccelerometerHardwareBufferFast" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testGyroscopeHardwareBufferFast" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testMagneticFieldHardwareBufferFast" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAccelerometerHardwareBufferVeryFast" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testGyroscopeHardwareBufferVeryFast" />
- <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testMagneticFieldHardwareBufferVeryFast" />
+ <!-- b/36686383 -->
+ <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" />
+
+ <!-- b/33090965 -->
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080" />
+
+ <!-- b/37105075 -->
+ <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.BatteryStatsValidationTest#testWifiUpload" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-vendor-interface.xml b/tools/cts-tradefed/res/config/cts-vendor-interface.xml
index 582cebf..6785dd8 100644
--- a/tools/cts-tradefed/res/config/cts-vendor-interface.xml
+++ b/tools/cts-tradefed/res/config/cts-vendor-interface.xml
@@ -44,6 +44,7 @@
<option name="compatibility:include-filter" value="CtsMonkeyTestCases" />
<option name="compatibility:include-filter" value="CtsNetTestCases" />
<option name="compatibility:include-filter" value="CtsOsTestCases" />
+ <option name="compatibility:include-filter" value="CtsPdfTestCases" />
<option name="compatibility:include-filter" value="CtsPreference2TestCases" />
<option name="compatibility:include-filter" value="CtsPrintTestCases" />
<option name="compatibility:include-filter" value="CtsProviderTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
index 28a5c27..0e31afb 100644
--- a/tools/cts-tradefed/res/config/cts.xml
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -24,6 +24,10 @@
<option name="test-tag" value="cts" />
<option name="enable-root" value="false" />
+ <!-- retain 200MB of host log -->
+ <option name="max-log-size" value="200" />
+ <!-- retain 200MB of logcat -->
+ <option name="max-tmp-logcat-file" value="209715200" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
<option name="property-name" value="ro.build.type" />
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index 31ee446..7e9c304 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -73,6 +73,10 @@
devicePolicyFile.deleteOnExit();
mDevice.pullFile("/sys/fs/selinux/policy", devicePolicyFile);
}
+
+ private boolean isFullTrebleDevice() throws Exception {
+ return android.security.cts.SELinuxHostTest.isFullTrebleDevice(mDevice);
+ }
"""
src_body = ""
src_footer = """}
@@ -82,6 +86,12 @@
@RestrictedBuildTest
public void testNeverallowRules() throws Exception {
String neverallowRule = "$NEVERALLOW_RULE_HERE$";
+ boolean fullTrebleOnly = $FULL_TREBLE_ONLY_BOOL_HERE$;
+
+ if ((fullTrebleOnly) && (!isFullTrebleDevice())) {
+ // This test applies only to Treble devices but this device isn't one
+ return;
+ }
/* run sepolicy-analyze neverallow check on policy file using given neverallow rules */
ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
diff --git a/tools/selinux/SELinuxNeverallowTestGen.py b/tools/selinux/SELinuxNeverallowTestGen.py
index 6194e2d..e74ba78 100755
--- a/tools/selinux/SELinuxNeverallowTestGen.py
+++ b/tools/selinux/SELinuxNeverallowTestGen.py
@@ -4,35 +4,82 @@
import sys
import SELinuxNeverallowTestFrame
-usage = "Usage: ./gen_SELinux_CTS_neverallows.py <input policy file> <output cts java source>"
+usage = "Usage: ./SELinuxNeverallowTestGen.py <input policy file> <output cts java source>"
+
+
+class NeverallowRule:
+ statement = ''
+ treble_only = False
+
+ def __init__(self, statement):
+ self.statement = statement
+ self.treble_only = False
+
# extract_neverallow_rules - takes an intermediate policy file and pulls out the
# neverallow rules by taking all of the non-commented text between the 'neverallow'
# keyword and a terminating ';'
-# returns: a list of strings representing these rules
+# returns: a list of rules
def extract_neverallow_rules(policy_file):
with open(policy_file, 'r') as in_file:
policy_str = in_file.read()
+
+ # full-Treble only tests are inside sections delimited by BEGIN_TREBLE_ONLY
+ # and END_TREBLE_ONLY comments.
+
+ # uncomment TREBLE_ONLY section delimiter lines
+ remaining = re.sub(
+ r'^\s*#\s*(BEGIN_TREBLE_ONLY|END_TREBLE_ONLY)',
+ r'\1',
+ policy_str,
+ flags = re.M)
# remove comments
- no_comments = re.sub(r'#.+?$', r'', policy_str, flags = re.M)
+ remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M)
# match neverallow rules
- return re.findall(r'^\s*(neverallow\s.+?;)', no_comments, flags = re.M |re.S);
+ lines = re.findall(
+ r'^\s*(neverallow\s.+?;|BEGIN_TREBLE_ONLY|END_TREBLE_ONLY)',
+ remaining,
+ flags = re.M |re.S)
+
+ # extract neverallow rules from the remaining lines
+ rules = list()
+ treble_only_depth = 0
+ for line in lines:
+ if line.startswith("BEGIN_TREBLE_ONLY"):
+ treble_only_depth += 1
+ continue
+ elif line.startswith("END_TREBLE_ONLY"):
+ if treble_only_depth < 1:
+ exit("ERROR: END_TREBLE_ONLY outside of TREBLE_ONLY section")
+ treble_only_depth -= 1
+ continue
+ rule = NeverallowRule(line)
+ rule.treble_only = (treble_only_depth > 0)
+ rules.append(rule)
+
+ if treble_only_depth != 0:
+ exit("ERROR: end of input while inside TREBLE_ONLY section")
+ return rules
# neverallow_rule_to_test - takes a neverallow statement and transforms it into
# the output necessary to form a cts unit test in a java source file.
# returns: a string representing a generic test method based on this rule.
-def neverallow_rule_to_test(neverallow_rule, test_num):
- squashed_neverallow = neverallow_rule.replace("\n", " ")
+def neverallow_rule_to_test(rule, test_num):
+ squashed_neverallow = rule.statement.replace("\n", " ")
method = SELinuxNeverallowTestFrame.src_method
method = method.replace("testNeverallowRules()",
"testNeverallowRules" + str(test_num) + "()")
- return method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
+ method = method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
+ method = method.replace(
+ "$FULL_TREBLE_ONLY_BOOL_HERE$",
+ "true" if rule.treble_only else "false")
+ return method
if __name__ == "__main__":
# check usage
if len(sys.argv) != 3:
print usage
- exit()
+ exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 6e29a24..d5811c3 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -89,13 +89,13 @@
$(LOCAL_BUILT_MODULE): PRIVATE_CLASS_PATH := $(subst $(space),:,$(vmteststf_dep_jars)):$(HOST_JDK_TOOLS_JAR)
$(LOCAL_BUILT_MODULE): PRIVATE_JACK_VERSION := $(LOCAL_JACK_VERSION)
ifndef LOCAL_JACK_ENABLED
-$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
+$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar
$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
# generated and compile the host side junit tests
@echo "Write generated Main_*.java files to $(PRIVATE_INTERMEDIATES_MAIN_FILES)"
$(hide) java -cp $(PRIVATE_CLASS_PATH) util.build.BuildDalvikSuite $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
- $(HOST_OUT_JAVA_LIBRARIES)/cts-tf-dalvik-buildutil.jar:$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar \
+ $(HOST_OUT_JAVA_LIBRARIES)/cts-tf-dalvik-buildutil.jar:$(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar \
$(PRIVATE_INTERMEDIATES_MAIN_FILES) $(PRIVATE_INTERMEDIATES_CLASSES) $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES) $$RUN_VM_TESTS_RTO
@echo "Generate $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)"
$(hide) jar -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).jar \