Merge "Test newly added batterystats background stats" 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/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/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/targetprep/NetworkConnectivityChecker.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
index 5479474..d77d931 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
@@ -19,6 +19,7 @@
import com.android.compatibility.common.util.MonitoringUtils;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.suite.checker.ISystemStatusChecker;
/**
@@ -26,14 +27,23 @@
*/
public class NetworkConnectivityChecker implements ISystemStatusChecker {
+ // Only report is as failed (capture bugreport) when status goes from pass-> fail
+ private boolean mIsFailed = false;
+
/**
* {@inheritDoc}
*/
@Override
public boolean postExecutionCheck(ITestDevice device) throws DeviceNotAvailableException {
if (!MonitoringUtils.checkDeviceConnectivity(device)) {
+ if (mIsFailed) {
+ CLog.w("NetworkConnectivityChecker is still failing.");
+ return true;
+ }
+ mIsFailed = true;
return false;
}
+ mIsFailed = false;
return true;
}
}
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..cd80500 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.tradefed.util.UniqueModuleCountUtil;
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;
@@ -56,15 +57,11 @@
import com.android.tradefed.util.ArrayUtil;
import com.android.tradefed.util.StreamUtil;
import com.android.tradefed.util.TimeUtil;
-import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
import com.google.common.annotations.VisibleForTesting;
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -153,10 +150,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 +158,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;
@@ -360,6 +353,15 @@
// Add the entire list of modules to the CompatibilityBuildHelper for reporting
mBuildHelper.setModuleIds(mModuleRepo.getModuleIds());
+
+ int count = UniqueModuleCountUtil.countUniqueModules(
+ mModuleRepo.getTokenModules()) +
+ UniqueModuleCountUtil.countUniqueModules(
+ mModuleRepo.getNonTokenModules());
+ CLog.logAndDisplay(LogLevel.INFO, "========================================");
+ CLog.logAndDisplay(LogLevel.INFO, "Starting a run with %s unique modules.",
+ count);
+ CLog.logAndDisplay(LogLevel.INFO, "========================================");
} else {
CLog.d("ModuleRepo already initialized.");
}
@@ -386,8 +388,10 @@
}
return;
} else {
- CLog.logAndDisplay(LogLevel.INFO, "Starting %d module%s on %s", moduleCount,
- (moduleCount > 1) ? "s" : "", mDevice.getSerialNumber());
+ int uniqueModuleCount = UniqueModuleCountUtil.countUniqueModules(modules);
+ CLog.logAndDisplay(LogLevel.INFO, "Starting %d test sub-module%s on %s",
+ uniqueModuleCount, (uniqueModuleCount > 1) ? "s" : "",
+ mDevice.getSerialNumber());
}
if (mRebootBeforeTest) {
@@ -671,113 +675,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/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index 794e45e..ea76919 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -18,6 +18,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.TestRunHandler;
import com.android.compatibility.common.tradefed.util.LinearPartition;
+import com.android.compatibility.common.tradefed.util.UniqueModuleCountUtil;
import com.android.compatibility.common.util.TestFilter;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
@@ -491,14 +492,19 @@
if (mInitCount == (mTotalShards - 1) &&
mTokenModuleScheduled.size() != mTokenModules.size()) {
mTokenModules.removeAll(mTokenModuleScheduled);
- CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+ if (mTotalShards != 1) {
+ // Only print the warnings if we are sharding.
+ CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+ }
modules.addAll(mTokenModules);
}
mInitCount++;
}
Collections.sort(modules, new ExecutionOrderComparator());
- CLog.logAndDisplay(LogLevel.INFO, "%s running %s modules, expected to complete in %s: %s",
- serial, modules.size(), TimeUtil.formatElapsedTime(estimatedTime), modules);
+ int uniqueCount = UniqueModuleCountUtil.countUniqueModules(modules);
+ CLog.logAndDisplay(LogLevel.INFO, "%s running %s test sub-modules, expected to complete "
+ + "in %s.", serial, uniqueCount, TimeUtil.formatElapsedTime(estimatedTime));
+ CLog.d("module list for this shard: %s", modules);
LinkedList<IModuleDef> tests = new LinkedList<>();
tests.addAll(modules);
return tests;
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/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java
new file mode 100644
index 0000000..e801ab3
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.IModuleDef;
+
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Utility to count the number of unique module from list of {@link IModuleDef}.
+ */
+public class UniqueModuleCountUtil {
+
+ /**
+ * Count the number of unique modules within the list using module id. If two IModuleDef have
+ * the same id, they are part of the same module.
+ *
+ * @param listModules list of {@link IModuleDef} to count from
+ * @return the count of unique module.
+ */
+ public static int countUniqueModules(List<IModuleDef> listModules) {
+ HashSet<String> uniqueNames = new HashSet<>();
+ for (IModuleDef subModule : listModules) {
+ uniqueNames.add(subModule.getId());
+ }
+ return uniqueNames.size();
+ }
+}
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..4e7c8c2 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,8 @@
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 com.android.compatibility.common.tradefed.util.UniqueModuleCountUtilTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -67,7 +69,7 @@
ConsoleReporterTest.class,
MetadataReporterTest.class,
ResultReporterTest.class,
- SubPlanCreatorTest.class,
+ SubPlanHelperTest.class,
// targetprep
PropertyCheckTest.class,
@@ -84,6 +86,8 @@
// util
CollectorUtilTest.class,
OptionHelperTest.class,
+ RetryFilterHelperTest.class,
+ UniqueModuleCountUtilTest.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/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
new file mode 100644
index 0000000..799cff3
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+import com.android.compatibility.common.tradefed.testtype.ModuleDef;
+import com.android.compatibility.common.tradefed.testtype.TestStub;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.Abi;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link UniqueModuleCountUtil}.
+ */
+public class UniqueModuleCountUtilTest {
+
+ @Test
+ public void testCountEmptyList() {
+ List<IModuleDef> emptyList = new ArrayList<>();
+ assertEquals(0, UniqueModuleCountUtil.countUniqueModules(emptyList));
+ }
+
+ @Test
+ public void testCount_2uniquesModules() {
+ List<IModuleDef> list = new ArrayList<>();
+ list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ assertEquals(2, UniqueModuleCountUtil.countUniqueModules(list));
+ }
+
+ @Test
+ public void testCount_2subModules() {
+ List<IModuleDef> list = new ArrayList<>();
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ assertEquals(1, UniqueModuleCountUtil.countUniqueModules(list));
+ }
+
+ @Test
+ public void testCount_mix() {
+ List<IModuleDef> list = new ArrayList<>();
+ list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleB", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleB", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleC", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ assertEquals(6, UniqueModuleCountUtil.countUniqueModules(list));
+ }
+}
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/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index 78f4a78..e0ac96f 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -47,6 +47,7 @@
private static final String UNEXPOSED_PKG = "com.android.cts.unexposedapp";
private static final String TEST_CLASS = ".ClientTest";
+ private static final String WEBVIEW_TEST_CLASS = ".WebViewTest";
private String mOldVerifierValue;
private IAbi mAbi;
@@ -120,6 +121,10 @@
runDeviceTests(EPHEMERAL_1_PKG, TEST_CLASS, "testPackageInfo");
}
+ public void testWebViewLoads() throws Exception {
+ runDeviceTests(EPHEMERAL_1_PKG, WEBVIEW_TEST_CLASS, "testWebViewLoads");
+ }
+
private void runDeviceTests(String packageName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
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/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
index 672bcd4..b13432b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
@@ -17,11 +17,14 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_JAVA_LIBRARIES := \
cts-aia-util \
android-support-test \
- legacy-android-test
+ legacy-android-test \
+ ctsdeviceutillegacy \
+ ctstestrunner
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
index e591c25..b0f53e0 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>
+ <activity android:name=".WebViewTestActivity" />
<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..12797a1 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;
@@ -125,7 +127,7 @@
filter.addCategory(Intent.CATEGORY_DEFAULT);
mReceiver = new ActivityBroadcastReceiver(mResultQueue);
InstrumentationRegistry.getContext()
- .registerReceiver(mReceiver, filter, true /*visibleToEmphemeral*/);
+ .registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
@After
@@ -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/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java
new file mode 100644
index 0000000..11d1c60
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+
+import android.webkit.WebView;
+import android.webkit.cts.WebViewOnUiThread;
+
+public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewTestActivity> {
+
+ private WebView mWebView;
+ private WebViewOnUiThread mOnUiThread;
+
+ public WebViewTest() {
+ super("com.android.cts.ephemeralapp1", WebViewTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final WebViewTestActivity activity = getActivity();
+ mWebView = activity.getWebView();
+ mOnUiThread = new WebViewOnUiThread(this, mWebView);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mOnUiThread.cleanUp();
+ super.tearDown();
+ }
+
+ @UiThreadTest
+ public void testWebViewLoads() throws Exception {
+ mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java
new file mode 100644
index 0000000..aae2b65
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java
@@ -0,0 +1,56 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.webkit.WebView;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+
+public class WebViewTestActivity extends Activity {
+ private WebView mWebView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ mWebView = new WebView(this);
+ setContentView(mWebView);
+ } catch (Exception e) {
+ NullWebViewUtils.determineIfWebViewAvailable(this, e);
+ }
+ }
+
+ public WebView getWebView() {
+ return mWebView;
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mWebView != null) {
+ ViewParent parent = mWebView.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(mWebView);
+ }
+ mWebView.destroy();
+ }
+ super.onDestroy();
+ }
+}
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..22b8c25 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;
@@ -73,7 +76,7 @@
filter.addCategory(Intent.CATEGORY_DEFAULT);
mReceiver = new ActivityBroadcastReceiver(mResultQueue);
InstrumentationRegistry.getContext()
- .registerReceiver(mReceiver, filter, true /*visibleToEmphemeral*/);
+ .registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
@After
@@ -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/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/InstantCookieApp/src/test/instant/cookie/CookieTest.java b/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
index 37f6bba..774296b 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class CookieTest {
@@ -36,18 +37,23 @@
assertTrue(pm.isInstantApp());
// The max cookie size is greater than zero
- assertTrue(pm.getInstantAppCookieMaxSize() > 0);
+ assertTrue(pm.getInstantAppCookieMaxBytes() > 0);
// Initially there is no cookie
byte[] cookie = pm.getInstantAppCookie();
assertTrue(cookie != null && cookie.length == 0);
// Setting a cookie below max size should work
- assertTrue(pm.setInstantAppCookie("1".getBytes()));
+ pm.updateInstantAppCookie("1".getBytes());
// Setting a cookie above max size should not work
- assertFalse(pm.setInstantAppCookie(
- new byte[pm.getInstantAppCookieMaxSize() + 1]));
+ try {
+ pm.updateInstantAppCookie(
+ new byte[pm.getInstantAppCookieMaxBytes() + 1]);
+ fail("Shouldn't be able to set a cookie larger than max size");
+ } catch (IllegalArgumentException e) {
+ /* expected */
+ }
// Ensure cookie not modified
assertEquals("1", new String(pm.getInstantAppCookie()));
@@ -58,7 +64,7 @@
PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
// Set a cookie to later check when reinstalled as instant app
- assertTrue(pm.setInstantAppCookie("2".getBytes()));
+ pm.updateInstantAppCookie("2".getBytes());
}
@Test
@@ -77,7 +83,7 @@
assertTrue(pm.isInstantApp());
// Set a cookie to later check when upgrade to a normal app
- assertTrue(pm.setInstantAppCookie("3".getBytes()));
+ pm.updateInstantAppCookie("3".getBytes());
}
@Test
@@ -96,7 +102,7 @@
PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
// Set a cookie to later check when reinstalled as normal app
- assertTrue(pm.setInstantAppCookie("4".getBytes()));
+ pm.updateInstantAppCookie("4".getBytes());
}
@Test
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/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/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/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 4bd993e..a35574b 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -25,6 +25,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -126,7 +127,12 @@
public void testAccessPrimaryProfileFromManagedProfile() throws Exception {
// Try to access main profile from managed profile, which is not allowed.
assertEquals(0, mLauncherApps.getActivityList(null, mUser).size());
- assertNull(mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser));
+ try {
+ mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser);
+ fail("Missing exception");
+ } catch (PackageManager.NameNotFoundException e) {
+ // Expected.
+ }
assertFalse(mLauncherApps.isPackageEnabled(SIMPLE_APP_PACKAGE, mUser));
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com/"));
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/incident/apps/batterystatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
index d4937aa..5e1198f 100644
--- a/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
+++ b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
@@ -18,6 +18,8 @@
package="com.android.server.cts.device.batterystats" >
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
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
index a02fe83..496e61a 100644
--- 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
@@ -45,6 +45,7 @@
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
index 7528cac..480ca2f 100644
--- 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
@@ -16,11 +16,19 @@
package com.android.server.cts.device.batterystats;
+import android.accounts.Account;
+import android.app.Activity;
import android.app.ActivityManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
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;
@@ -31,6 +39,7 @@
import android.os.Looper;
import android.util.Log;
+
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -39,8 +48,13 @@
private static final String TAG = BatteryStatsBgVsFgActions.class.getSimpleName();
public static final String KEY_ACTION = "action";
+ public static final String ACTION_BLE_SCAN = "action.ble_scan";
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) {
@@ -50,11 +64,23 @@
}
sleep(100);
switch(actionCode) {
+ case ACTION_BLE_SCAN:
+ doBleScan(ctx);
+ break;
case ACTION_JOB_SCHEDULE:
doScheduleJob(ctx);
break;
+ case ACTION_SYNC:
+ doSync(ctx);
+ break;
case ACTION_WIFI_SCAN:
- doWifi(ctx);
+ 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");
@@ -62,6 +88,48 @@
sleep(100);
}
+ private static void doBleScan(Context ctx) {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (bluetoothAdapter == null) {
+ Log.e(TAG, "Device does not support Bluetooth");
+ return;
+ }
+ if (!bluetoothAdapter.isEnabled()) {
+ Log.e(TAG, "Bluetooth is not enabled");
+ return;
+ }
+
+ BluetoothLeScanner bleScanner = bluetoothAdapter.getBluetoothLeScanner();
+ if (bleScanner == null) {
+ Log.e(TAG, "Cannot access BLE scanner");
+ return;
+ }
+
+ ScanCallback scanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ Log.v(TAG, "called onScanResult");
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ Log.v(TAG, "called onScanFailed");
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ Log.v(TAG, "called onBatchScanResults");
+
+ }
+ };
+ ScanSettings scanSettings = new ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+
+ bleScanner.startScan(null, scanSettings, scanCallback);
+ sleep(2_000);
+ bleScanner.stopScan(scanCallback);
+ }
+
private static void doScheduleJob(Context ctx) {
final ComponentName JOB_COMPONENT_NAME =
new ComponentName("com.android.server.cts.device.batterystats",
@@ -86,7 +154,42 @@
}.execute();
}
- private static void doWifi(Context ctx) {
+ 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);
@@ -94,6 +197,26 @@
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) {
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
index d6869a1..c41b244 100644
--- 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
@@ -18,6 +18,7 @@
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;
@@ -51,7 +52,12 @@
Log.w(TAG, "Couldn't determine if app is in foreground. Proceeding with test anyway");
}
- doAction(this, intent.getStringExtra(KEY_ACTION));
- finish();
+ 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/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 f6e9e31..758c443 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -38,11 +38,19 @@
= "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_BLE_SCAN = "action.ble_scan";
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 {
@@ -117,6 +125,25 @@
batteryOffScreenOn();
}
+ public void testBleScans() throws Exception {
+ batteryOnScreenOff();
+ installPackage(DEVICE_SIDE_TEST_APK, true);
+
+ // Foreground test.
+ executeForeground(ACTION_BLE_SCAN);
+ Thread.sleep(2_500);
+ assertValueRange("blem", "", 5, 1, 1); // ble_scan_count
+ assertValueRange("blem", "", 6, 0, 0); // ble_scan_count_bg
+
+ // Background test.
+ executeBackground(ACTION_BLE_SCAN);
+ Thread.sleep(2_500);
+ assertValueRange("blem", "", 5, 2, 2); // ble_scan_count
+ assertValueRange("blem", "", 6, 1, 1); // ble_scan_count_bg
+
+ batteryOffScreenOn();
+ }
+
public void testJobBgVsFg() throws Exception {
batteryOnScreenOff();
installPackage(DEVICE_SIDE_TEST_APK, true);
@@ -136,6 +163,26 @@
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);
@@ -148,7 +195,7 @@
// Background count test.
executeBackground(ACTION_WIFI_SCAN);
- Thread.sleep(4_000);
+ Thread.sleep(6_000);
assertValueRange("wfl", "", 7, 2, 2); // scan_count
assertValueRange("wfl", "", 11, 1, 1); // scan_count_bg
@@ -224,23 +271,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 + (30 * 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 + (30 * 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();
}
@@ -252,33 +310,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);
@@ -344,13 +406,14 @@
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/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
index d8f2f75..f4c0698 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
@@ -22,7 +22,6 @@
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_CREATE;
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_DESTROY;
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_START_INPUT;
-import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_START_INPUT_VIEW;
import static android.inputmethodservice.cts.common.ImeCommandConstants.ACTION_IME_COMMAND;
import static android.inputmethodservice.cts.common.ImeCommandConstants.COMMAND_SWITCH_INPUT_METHOD;
import static android.inputmethodservice.cts.common.ImeCommandConstants.EXTRA_ARG_STRING1;
@@ -54,9 +53,7 @@
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
- /**
- * Test to check {@link Ime1Constants} receives onCreate, onStartInput, and onStartInputView.
- */
+ /** Test to check CtsInputMethod1 receives onCreate and onStartInput. */
@Test
public void testCreateIme1() throws Throwable {
final TestHelper helper = new TestHelper(getClass(), DeviceTestConstants.TEST_CREATE_IME1);
@@ -65,7 +62,7 @@
.collect(startingFrom(helper.isStartOfTest()))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_CREATE)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onCreate is called");
+ TIMEOUT, "CtsInputMethod1.onCreate is called");
final long startActivityTime = SystemClock.uptimeMillis();
helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
@@ -74,18 +71,10 @@
.filter(isNewerThan(startActivityTime))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInput is called");
-
- final long touchEntryTime = SystemClock.uptimeMillis();
- helper.findUiObject(R.id.text_entry).click();
-
- pollingCheck(() -> helper.queryAllEvents()
- .filter(isNewerThan(touchEntryTime))
- .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT_VIEW)))
- .findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInputView is called");
+ TIMEOUT, "CtsInputMethod1.onStartInput is called");
}
+ /** Test to check IME is switched from CtsInputMethod1 to CtsInputMethod2. */
@Test
public void testSwitchIme1ToIme2() throws Throwable {
final TestHelper helper = new TestHelper(
@@ -95,7 +84,7 @@
.collect(startingFrom(helper.isStartOfTest()))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_CREATE)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onCreate is called");
+ TIMEOUT, "CtsInputMethod1.onCreate is called");
final long startActivityTime = SystemClock.uptimeMillis();
helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
@@ -104,18 +93,11 @@
.filter(isNewerThan(startActivityTime))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInput is called");
+ TIMEOUT, "CtsInputMethod1.onStartInput is called");
- final long touchEntryTime = SystemClock.uptimeMillis();
helper.findUiObject(R.id.text_entry).click();
- pollingCheck(() -> helper.queryAllEvents()
- .filter(isNewerThan(touchEntryTime))
- .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT_VIEW)))
- .findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInputView is called");
-
- // Switch IME from Ime1Constants to Ime2Constants.
+ // Switch IME from CtsInputMethod1 to CtsInputMethod2.
final long switchImeTime = SystemClock.uptimeMillis();
helper.shell(ShellCommandUtils.broadcastIntent(
ACTION_IME_COMMAND, Ime1Constants.PACKAGE,
@@ -124,21 +106,22 @@
pollingCheck(() -> helper.shell(ShellCommandUtils.getCurrentIme())
.equals(Ime2Constants.IME_ID),
- TIMEOUT, "Ime2Constants is current IME");
+ TIMEOUT, "CtsInputMethod2 is current IME");
pollingCheck(() -> helper.queryAllEvents()
.filter(isNewerThan(switchImeTime))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_DESTROY)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onDestroy is called");
+ TIMEOUT, "CtsInputMethod1.onDestroy is called");
pollingCheck(() -> helper.queryAllEvents()
.filter(isNewerThan(switchImeTime))
.filter(isFrom(Ime2Constants.CLASS))
- .collect(sequenceOfTypes(ON_CREATE, ON_START_INPUT, ON_START_INPUT_VIEW))
+ .collect(sequenceOfTypes(ON_CREATE, ON_START_INPUT))
.matched(),
TIMEOUT,
- "Ime2Constants.onCreate,onStartInput,onStartInputView are called in sequence");
+ "CtsInputMethod2.onCreate and onStartInput are called in sequence");
}
+ /** Test to check CtsInputMethod1 isn't current IME. */
@Test
public void testIme1IsNotCurrentIme() throws Throwable {
final TestHelper helper =
@@ -150,7 +133,7 @@
pollingCheck(() -> !helper.shell(ShellCommandUtils.getCurrentIme())
.equals(Ime1Constants.IME_ID),
TIMEOUT,
- "Ime1Constants is uninstalled or disabled, and current IME becomes other IME");
+ "CtsInputMethod1 is uninstalled or disabled, and current IME becomes other IME");
}
/**
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..577f62c 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();
}
}
@@ -817,9 +833,7 @@
}
if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
if (!errors[0].isEmpty()) {
- // TODO: revert this change once b/35523062 is fixed.
-// fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
- assertForegroundNetworkAccess();
+ fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
}
} else {
fail("Timed out waiting for network availability status from app2 (" + mUid + ")");
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/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
index ad77b03..4be6ffe 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
@@ -101,7 +101,7 @@
List<VersionedPackage> dependentPackages = sharedLib.getDependentPackages();
- switch (sharedLib.getVersion()) {
+ switch ((int) sharedLib.getVersion()) {
case 1: {
firstLibFound = true;
assertSame(1, declaringPackage.getVersionCode());
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 8ed60e6..46779de 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -251,9 +251,9 @@
/**
* 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()) {
@@ -273,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()) {
@@ -295,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/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index 3cdc754..ade0963 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -27,8 +27,14 @@
<application>
<activity android:name=".TestActivity"
android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
android:exported="true"
/>
+ <activity android:name=".TranslucentTestActivity"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:theme="@style/Theme.Transparent" />
<activity android:name=".VrTestActivity"
android:resizeableActivity="true"
android:exported="true"
@@ -90,6 +96,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"
@@ -105,12 +119,6 @@
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true"
/>
- <activity android:name=".VisibleBehindActivity"
- android:resizeableActivity="false"
- android:supportsPictureInPicture="true"
- android:exported="true"
- android:taskAffinity="nobody.but.VisibleBehindActivity"
- />
<activity android:name=".LaunchPipOnPipActivity"
android:resizeableActivity="false"
android:supportsPictureInPicture="true"
@@ -325,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/layout/task_overlay.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml
new file mode 100644
index 0000000..67e0b08
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#800000ff">
+</FrameLayout>
\ No newline at end of file
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/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index 7e116a9..7b8a695 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -40,6 +40,12 @@
}
@Override
+ protected void onResume() {
+ super.onResume();
+ Log.i(getTag(), "onResume");
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i(getTag(), "onConfigurationChanged");
@@ -76,6 +82,18 @@
}
@Override
+ protected void onPause() {
+ super.onPause();
+ Log.i(getTag(), "onPause");
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ Log.i(getTag(), "onStop");
+ }
+
+ @Override
protected void onDestroy() {
super.onDestroy();
Log.i(getTag(), "onDestroy");
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
index 0d49519..f60abfa 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -50,6 +50,8 @@
// Will apply the oriention to the value set in the EXTRA_FIXED_ORIENTATION extra.
private static final String ACTION_SET_REQUESTED_ORIENTATION =
"android.server.cts.PipActivity.set_requested_orientation";
+ // Intent action that will finish this activity
+ private static final String ACTION_FINISH = "android.server.cts.PipActivity.finish";
// Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
@@ -115,6 +117,9 @@
setRequestedOrientation(Integer.parseInt(intent.getStringExtra(
EXTRA_FIXED_ORIENTATION)));
break;
+ case ACTION_FINISH:
+ finish();
+ break;
}
}
}
@@ -177,17 +182,14 @@
launchIntent.setComponent(ComponentName.unflattenFromString(launchActivityComponent));
startActivity(launchIntent);
}
- }
- @Override
- protected void onStart() {
- super.onStart();
-
+ // Register the broadcast receiver
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_ENTER_PIP);
filter.addAction(ACTION_MOVE_TO_BACK);
filter.addAction(ACTION_EXPAND_PIP);
filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
+ filter.addAction(ACTION_FINISH);
registerReceiver(mReceiver, filter);
}
@@ -219,7 +221,6 @@
@Override
protected void onStop() {
super.onStop();
- unregisterReceiver(mReceiver);
if (getIntent().hasExtra(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP) && !mEnteredPictureInPicture) {
Log.w("PipActivity", "Unexpected onStop() called before entering picture-in-picture");
@@ -228,6 +229,13 @@
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ unregisterReceiver(mReceiver);
+ }
+
+ @Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
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/TestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
index 567cbbb..ec45357 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
@@ -55,17 +55,22 @@
}
@Override
+ protected void onStart() {
+ super.onStart();
+ registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
+ }
+
+ @Override
protected void onResume() {
super.onResume();
- registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
final Configuration config = getResources().getConfiguration();
dumpDisplaySize(config);
dumpConfiguration(config);
}
@Override
- protected void onPause() {
- super.onPause();
+ protected void onStop() {
+ super.onStop();
unregisterReceiver(mReceiver);
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java
new file mode 100644
index 0000000..1d10a51
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.cts;
+
+import android.os.Bundle;
+
+public class TranslucentTestActivity extends TestActivity {
+
+ private static final String TAG = TranslucentTestActivity.class.getSimpleName();
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.task_overlay);
+ }
+
+ @Override
+ protected String getTag() {
+ return TAG;
+ }
+}
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/app/src/android/server/cts/VisibleBehindActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
deleted file mode 100644
index 29feba9..0000000
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.server.cts;
-
-import android.app.Activity;
-import android.util.Log;
-
-public class VisibleBehindActivity extends Activity {
- private static final String TAG = "VisibleBehindActivity";
- @Override
- protected void onPause() {
- super.onPause();
- if (requestVisibleBehind(true)) {
- Log.e(TAG, "Failed to request visibility behind...");
- }
- }
-}
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..d0db632 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -18,16 +18,21 @@
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
*/
public class ActivityManagerActivityVisibilityTests extends ActivityManagerTestBase {
private static final String TRANSLUCENT_ACTIVITY = "AlwaysFocusablePipActivity";
- private static final String VISIBLE_BEHIND_ACTIVITY = "VisibleBehindActivity";
private static final String PIP_ON_PIP_ACTIVITY = "LaunchPipOnPipActivity";
private static final String TEST_ACTIVITY_NAME = "TestActivity";
private static final String TRANSLUCENT_ACTIVITY_NAME = "TranslucentActivity";
@@ -35,46 +40,6 @@
private static final String TURN_SCREEN_ON_ACTIVITY_NAME = "TurnScreenOnActivity";
private static final String MOVE_TASK_TO_BACK_ACTIVITY_NAME = "MoveTaskToBackActivity";
- public void testVisibleBehindHomeActivity() throws Exception {
- launchActivity(VISIBLE_BEHIND_ACTIVITY);
- mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY,
- FULLSCREEN_WORKSPACE_STACK_ID);
- launchHomeActivity();
-
- /* TODO: Find a proper way to wait until launcher activity
- * becomes fully visible. It appears that both VisibleBehindActivity
- * and home activity are visible at some point before the former
- * disappears.*/
- Thread.sleep(3000);
- mAmWmState.computeState(mDevice, null);
- mAmWmState.assertContainsStack(
- "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
- mAmWmState.assertFrontStack("Home stack must be the front stack.", HOME_STACK_ID);
- mAmWmState.assertVisibility(
- VISIBLE_BEHIND_ACTIVITY, hasDeviceFeature("android.software.leanback"));
- }
-
- public void testVisibleBehindOtherActivity_NotOverHome() throws Exception {
- launchActivity(VISIBLE_BEHIND_ACTIVITY);
- launchActivity(TRANSLUCENT_ACTIVITY);
-
- mAmWmState.computeState(mDevice,
- new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
- mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
- }
-
- public void testVisibleBehindOtherActivity_OverHome() throws Exception {
- executeShellCommand(getAmStartCmdOverHome(VISIBLE_BEHIND_ACTIVITY));
- mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY);
- executeShellCommand(getAmStartCmdOverHome(TRANSLUCENT_ACTIVITY));
-
- mAmWmState.computeState(mDevice,
- new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
- mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
- }
-
public void testTranslucentActivityOnTopOfPinnedStack() throws Exception {
if (!supportsPip()) {
return;
@@ -97,6 +62,10 @@
* fullscreen stack over the home activity.
*/
public void testTranslucentActivityOnTopOfHome() throws Exception {
+ if (noHomeScreen()) {
+ return;
+ }
+
launchHomeActivity();
launchActivity(TRANSLUCENT_ACTIVITY);
@@ -130,6 +99,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 +119,7 @@
mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY_NAME, true);
}
+ @Presubmit
public void testTurnScreenOnActivity() throws Exception {
sleepDevice();
launchActivity(TURN_SCREEN_ON_ACTIVITY_NAME);
@@ -153,6 +128,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 8d1a78e..31f82ac 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -55,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);
}
@@ -69,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);
}
@@ -83,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);
}
@@ -93,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.
@@ -102,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);
}
@@ -112,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;
@@ -139,7 +174,8 @@
return;
}
- final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+ final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ logSeparator);
assertSizesRotate(prevSizes, rotatedSizes);
prevSizes = rotatedSizes;
}
@@ -156,6 +192,7 @@
/**
* Same as {@link #testSameConfigurationFullSplitFullRelaunch} but without relaunch.
*/
+ @Presubmit
public void testSameConfigurationFullSplitFullNoRelaunch() throws Exception {
moveActivityFullSplitFull(RESIZEABLE_ACTIVITY_NAME);
}
@@ -168,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.
@@ -185,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);
@@ -347,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);
@@ -357,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);
@@ -424,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;
}
@@ -459,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 2b34735..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();
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..038eb8d 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -35,14 +35,16 @@
*/
public class ActivityManagerPinnedStackTests extends ActivityManagerTestBase {
private static final String TEST_ACTIVITY = "TestActivity";
+ private static final String TRANSLUCENT_TEST_ACTIVITY = "TranslucentTestActivity";
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";
private static final String LAUNCH_IME_WITH_PIP_ACTIVITY = "LaunchImeWithPipActivity";
- private static final String LAUNCHER_ENTER_PIP_ACTIVITY = "LaunchEnterPipActivity";
+ private static final String LAUNCH_ENTER_PIP_ACTIVITY = "LaunchEnterPipActivity";
private static final String PIP_ON_STOP_ACTIVITY = "PipOnStopActivity";
private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
@@ -64,8 +66,12 @@
"android.server.cts.PipActivity.move_to_back";
private static final String PIP_ACTIVITY_ACTION_EXPAND_PIP =
"android.server.cts.PipActivity.expand_pip";
- private static final String ACTION_SET_REQUESTED_ORIENTATION =
+ private static final String PIP_ACTIVITY_ACTION_SET_REQUESTED_ORIENTATION =
"android.server.cts.PipActivity.set_requested_orientation";
+ private static final String PIP_ACTIVITY_ACTION_FINISH =
+ "android.server.cts.PipActivity.finish";
+ private static final String TEST_ACTIVITY_ACTION_FINISH =
+ "android.server.cts.TestActivity.finish_self";
private static final int APP_OPS_OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
private static final int APP_OPS_MODE_ALLOWED = 0;
@@ -92,22 +98,25 @@
private static final float ABOVE_MAX_ASPECT_RATIO = MAX_ASPECT_RATIO + FLOAT_COMPARE_EPSILON;
public void testEnterPictureInPictureMode() throws Exception {
- pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"),
- PIP_ACTIVITY, false, false);
+ pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"), PIP_ACTIVITY,
+ false /* moveTopToPinnedStack */, false /* isFocusable */);
}
public void testMoveTopActivityToPinnedStack() throws Exception {
- pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY, true, false);
+ pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY,
+ true /* moveTopToPinnedStack */, false /* isFocusable */);
}
public void testAlwaysFocusablePipActivity() throws Exception {
pinnedStackTester(getAmStartCmd(ALWAYS_FOCUSABLE_PIP_ACTIVITY),
- ALWAYS_FOCUSABLE_PIP_ACTIVITY, true, true);
+ ALWAYS_FOCUSABLE_PIP_ACTIVITY, false /* moveTopToPinnedStack */,
+ true /* isFocusable */);
}
public void testLaunchIntoPinnedStack() throws Exception {
pinnedStackTester(getAmStartCmd(LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY),
- ALWAYS_FOCUSABLE_PIP_ACTIVITY, false, true);
+ ALWAYS_FOCUSABLE_PIP_ACTIVITY, false /* moveTopToPinnedStack */,
+ true /* isFocusable */);
}
public void testNonTappablePipActivity() throws Exception {
@@ -467,6 +476,30 @@
ALWAYS_FOCUSABLE_PIP_ACTIVITY)));
}
+ public void testDisallowMultipleTasksInPinnedStack() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch a test activity so that we have multiple fullscreen tasks
+ launchActivity(TEST_ACTIVITY);
+
+ // 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;
@@ -559,7 +592,7 @@
// stack, but that the home stack is still focused
removeStacks(PINNED_STACK_ID);
assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
- true /* expectTopTaskHasActivity */, false /* expectBottomTaskHasActivity */);
+ false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
}
public void testMovePipToBackWithNoFullscreenStack() throws Exception {
@@ -576,7 +609,7 @@
// fullscreen stack existed before)
executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_MOVE_TO_BACK);
assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
- true /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
+ false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
}
public void testMovePipToBackWithVisibleFullscreenStack() throws Exception {
@@ -608,7 +641,7 @@
// stack, but that the home stack is still focused
executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_MOVE_TO_BACK);
assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
- true /* expectTopTaskHasActivity */, false /* expectBottomTaskHasActivity */);
+ false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
}
public void testPinnedStackAlwaysOnTop() throws Exception {
@@ -655,7 +688,7 @@
// Try to enter picture-in-picture from an activity that has more than one activity in the
// task and ensure that it works
- launchActivity(LAUNCHER_ENTER_PIP_ACTIVITY);
+ launchActivity(LAUNCH_ENTER_PIP_ACTIVITY);
mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, PINNED_STACK_ID);
assertPinnedStackExists();
}
@@ -715,17 +748,54 @@
// 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 testStopBeforeMultiWindowCallbacksOnDismiss() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch a PiP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ assertPinnedStackExists();
+
+ // Dismiss it
+ String logSeparator = clearLogcat();
+ removeStacks(PINNED_STACK_ID);
+ mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID);
+
+ // Confirm that we get stop before the multi-window and picture-in-picture mode change
+ // callbacks
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY,
+ logSeparator);
+ if (lifecycleCounts.mStopCount != 1) {
+ fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mStopCount
+ + " onStop() calls, expecting 1");
+ } else if (lifecycleCounts.mPictureInPictureModeChangedCount != 1) {
+ fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mPictureInPictureModeChangedCount
+ + " onMultiWindowModeChanged() calls, expecting 1");
+ } else if (lifecycleCounts.mMultiWindowModeChangedCount != 1) {
+ fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mMultiWindowModeChangedCount
+ + " onPictureInPictureModeChanged() calls, expecting 1");
+ } else {
+ int lastStopLine = lifecycleCounts.mLastStopLineIndex;
+ int lastPipLine = lifecycleCounts.mLastPictureInPictureModeChangedLineIndex;
+ int lastMwLine = lifecycleCounts.mLastMultiWindowModeChangedLineIndex;
+ if (!(lastStopLine < lastPipLine && lastPipLine < lastMwLine)) {
+ fail(PIP_ACTIVITY + " has received callbacks in unexpected order. Expected:"
+ + " stop < pip < mw, but got line indices: " + lastStopLine + ", "
+ + lastPipLine + ", " + lastMwLine + " respectively");
+ }
+ }
}
public void testPreventSetAspectRatioWhileExpanding() throws Exception {
@@ -752,7 +822,8 @@
assertPinnedStackExists();
// Request that the orientation is set to landscape
- executeShellCommand("am broadcast -a " + ACTION_SET_REQUESTED_ORIENTATION + " -e "
+ executeShellCommand("am broadcast -a "
+ + PIP_ACTIVITY_ACTION_SET_REQUESTED_ORIENTATION + " -e "
+ EXTRA_FIXED_ORIENTATION + " " + String.valueOf(ORIENTATION_LANDSCAPE));
// Launch the activity back into fullscreen and ensure that it is now in landscape
@@ -772,6 +843,53 @@
assertPinnedStackExists();
}
+ public void testFinishPipActivityWithTaskOverlay() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch PiP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ assertPinnedStackExists();
+ int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
+
+ // Launch task overlay activity into PiP activity task
+ launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
+
+ // Finish the PiP activity and ensure that there is no pinned stack
+ executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_FINISH);
+ mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+ ActivityStack stack = amState.getStackById(PINNED_STACK_ID);
+ if (stack != null) {
+ return false;
+ }
+ return true;
+ }, "Waiting for pinned stack to be removed...");
+ assertPinnedStackDoesNotExist();
+ }
+
+ public void testNoResumeAfterTaskOverlayFinishes() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch PiP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ assertPinnedStackExists();
+ int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
+
+ // Launch task overlay activity into PiP activity task
+ launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
+
+ // Finish the task overlay activity while animating and ensure that the PiP activity never
+ // got resumed
+ String logSeparator = clearLogcat();
+ executeShellCommand("am stack resize-animated 4 20 20 500 500");
+ executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH);
+ mAmWmState.waitFor(mDevice, (amState, wmState) -> !amState.containsActivity(
+ TRANSLUCENT_TEST_ACTIVITY), "Waiting for test activity to finish...");
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY,
+ logSeparator);
+ assertTrue(lifecycleCounts.mResumeCount == 0);
+ assertTrue(lifecycleCounts.mPauseCount == 0);
+ }
+
/**
* Called after the given {@param activityName} has been moved to the fullscreen stack. Ensures
* that the {@param focusedStackId} is focused, and checks the top and/or bottom tasks in the
@@ -864,8 +982,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
@@ -918,6 +1038,16 @@
}
/**
+ * Launches the given {@param activityName} into the {@param taskId} as a task overlay.
+ */
+ private void launchActivityAsTaskOverlay(String activityName, int taskId, int stackId)
+ throws Exception {
+ executeShellCommand(getAmStartCmd(activityName) + " --task " + taskId + " --task-overlay");
+
+ mAmWmState.waitForValidState(mDevice, activityName, stackId);
+ }
+
+ /**
* Sets an app-ops op for a given package to a given mode.
*/
private void setAppOpsOpToMode(String packageName, int op, int mode) throws Exception {
@@ -931,6 +1061,10 @@
executeShellCommand(INPUT_KEYEVENT_WINDOW);
}
+ /**
+ * TODO: Improve tests check to actually check that apps are not interactive instead of checking
+ * if the stack is focused.
+ */
private void pinnedStackTester(String startActivityCmd, String topActivityName,
boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
@@ -958,8 +1092,8 @@
// Not checking for resumed state here because PiP overlay can be launched on top
// in different task by SystemUI.
} else {
- mAmWmState.assertNotFocusedStack(
- "Pinned stack can't be the focused stack.", PINNED_STACK_ID);
+ // Don't assert that the stack is not focused as a focusable PiP overlay can be
+ // launched on top as a task overlay by SystemUI.
mAmWmState.assertNotFocusedActivity(
"Pinned activity can't be the focused activity.", topActivityName);
mAmWmState.assertNotResumedActivity(
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..bfd6b5a 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,93 +724,194 @@
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");
+ private static final Pattern sResumePattern = Pattern.compile("(.+): onResume");
+ private static final Pattern sPausePattern = Pattern.compile("(.+): onPause");
private static final Pattern sConfigurationChangedPattern =
Pattern.compile("(.+): onConfigurationChanged");
private static final Pattern sMovedToDisplayPattern =
Pattern.compile("(.+): onMovedToDisplay");
+ private static final Pattern sStopPattern = Pattern.compile("(.+): onStop");
private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
private static final Pattern sMultiWindowModeChangedPattern =
Pattern.compile("(.+): onMultiWindowModeChanged");
@@ -819,9 +957,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);
@@ -843,6 +1002,7 @@
class ActivityLifecycleCounts {
int mCreateCount;
+ int mResumeCount;
int mConfigurationChangedCount;
int mLastConfigurationChangedLineIndex;
int mMovedToDisplayCount;
@@ -850,11 +1010,15 @@
int mLastMultiWindowModeChangedLineIndex;
int mPictureInPictureModeChangedCount;
int mLastPictureInPictureModeChangedLineIndex;
+ int mPauseCount;
+ int mStopCount;
+ int mLastStopLineIndex;
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++;
@@ -864,6 +1028,12 @@
continue;
}
+ matcher = sResumePattern.matcher(line);
+ if (matcher.matches()) {
+ mResumeCount++;
+ continue;
+ }
+
matcher = sConfigurationChangedPattern.matcher(line);
if (matcher.matches()) {
mConfigurationChangedCount++;
@@ -891,6 +1061,19 @@
continue;
}
+ matcher = sPausePattern.matcher(line);
+ if (matcher.matches()) {
+ mPauseCount++;
+ continue;
+ }
+
+ matcher = sStopPattern.matcher(line);
+ if (matcher.matches()) {
+ mStopCount++;
+ mLastStopLineIndex = lineIndex;
+ continue;
+ }
+
matcher = sDestroyPattern.matcher(line);
if (matcher.matches()) {
mDestroyCount++;
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..25f8317 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,9 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
public class ShortcutManagerBackupTest extends BaseShortcutManagerHostTest {
private static final String LAUNCHER1_APK = "CtsShortcutBackupLauncher1.apk";
private static final String LAUNCHER2_APK = "CtsShortcutBackupLauncher2.apk";
@@ -40,6 +43,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 +62,15 @@
clearShortcuts(PUBLISHER1_PKG, getPrimaryUserId());
clearShortcuts(PUBLISHER2_PKG, getPrimaryUserId());
clearShortcuts(PUBLISHER3_PKG, getPrimaryUserId());
+
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER3_PKG);
+
+ waitUntilPackagesGone();
}
}
@@ -106,10 +120,82 @@
}
+ private void uninstallPackageAndWaitUntilBroadcastsDrain(String pkg) throws Exception {
+ getDevice().uninstallPackage(pkg);
+ waitUntilBroadcastsDrain();
+ }
+
+ /**
+ * Wait until the broadcasts queues all drain.
+ */
+ private void waitUntilBroadcastsDrain() throws Exception {
+ final long TIMEOUT = System.nanoTime() +
+ TimeUnit.SECONDS.toNanos(BROADCAST_TIMEOUT_SECONDS);
+
+ final Pattern re = Pattern.compile("^\\s+Active (ordered)? broadcasts \\[",
+ Pattern.MULTILINE);
+
+ String dumpsys = "";
+ while (System.nanoTime() < TIMEOUT) {
+ Thread.sleep(1000);
+
+ dumpsys = getDevice().executeShellCommand("dumpsys activity broadcasts");
+
+ if (re.matcher(dumpsys).find()) {
+ continue;
+ }
+
+ CLog.d("Broadcast queues drained:\n" + dumpsys);
+
+ dumpsys("Broadcast queues drained");
+
+ // All packages gone.
+ return;
+ }
+ fail("Broadcast queues didn't drain before time out."
+ + " Last dumpsys=\n" + dumpsys);
+ }
+
+ /**
+ * 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("Shortcut manager handled broadcasts");
+
+ // 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,21 +217,31 @@
// Tweak shortcuts a little bit to make disabled shortcuts.
runDeviceTestsAsUser(PUBLISHER2_PKG, ".ShortcutManagerPreBackup2Test", getPrimaryUserId());
+ dumpsys("Before backup");
+
// Backup
doBackup();
// Uninstall all apps
- getDevice().uninstallPackage(LAUNCHER1_PKG);
- getDevice().uninstallPackage(LAUNCHER2_PKG);
- getDevice().uninstallPackage(LAUNCHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER3_PKG);
- getDevice().uninstallPackage(PUBLISHER1_PKG);
- getDevice().uninstallPackage(PUBLISHER2_PKG);
- getDevice().uninstallPackage(PUBLISHER3_PKG);
+
+ // Make sure the shortcut service handled all the uninstall broadcasts.
+ waitUntilPackagesGone();
+
+ // Do it one more time just in case...
+ waitUntilBroadcastsDrain();
// 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..c081df9 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;
@@ -57,7 +56,6 @@
mAccessibilityManager = (AccessibilityManager)
getInstrumentation().getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
mTargetContext = getInstrumentation().getTargetContext();
- ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
}
@Override
@@ -83,16 +81,8 @@
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 {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
new PollingCheck() {
@Override
protected boolean check() {
@@ -125,6 +115,7 @@
}
public void testGetEnabledAccessibilityServiceList() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
@@ -148,6 +139,7 @@
}
public void testGetEnabledAccessibilityServiceListForType() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_SPOKEN);
@@ -165,6 +157,7 @@
}
public void testGetEnabledAccessibilityServiceListForTypes() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
// For this test, also enable a service with multiple feedback types
ServiceControlUtils.enableMultipleFeedbackTypesService(getInstrumentation());
@@ -224,6 +217,7 @@
public void testInterrupt() throws Exception {
// The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
waitForAccessibilityEnabled();
mAccessibilityManager.interrupt();
}
@@ -231,62 +225,71 @@
public void testSendAccessibilityEvent() throws Exception {
// The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
waitForAccessibilityEnabled();
mAccessibilityManager.sendAccessibilityEvent(AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_VIEW_CLICKED));
}
- public void testTouchExplorationStateChanged() throws Exception {
- waitForTouchExplorationEnabled();
- }
-
- public void testServiceStateChanges_stateChangeListenersCalled() throws Exception {
+ public void testTouchExplorationListener() throws Exception {
final Object waitObject = new Object();
- final AtomicBoolean listenerCalled = new AtomicBoolean(false);
- final SpeakingAccessibilityService service =
- SpeakingAccessibilityService.sConnectedInstance;
- final AccessibilityServicesStateChangeListener listener = () -> {
+ final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
+
+ TouchExplorationStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
- listenerCalled.set(true);
+ atomicBoolean.set(b);
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);
+ mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
- assertListenerCalled(listenerCalled, waitObject);
-
- mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener);
-
+ assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
+ "Touch exploration state listener not called when services enabled");
+ assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
+ mAccessibilityManager.isTouchExplorationEnabled());
+ ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
+ "Touch exploration state listener not called when services disabled");
+ assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
+ mAccessibilityManager.isTouchExplorationEnabled());
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
}
- private void assertListenerCalled(AtomicBoolean listenerCalled, Object waitObject)
+ public void testAccessibilityStateListener() throws Exception {
+ final Object waitObject = new Object();
+ final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
+
+ AccessibilityStateChangeListener listener = (boolean b) -> {
+ synchronized (waitObject) {
+ atomicBoolean.set(b);
+ waitObject.notifyAll();
+ }
+ };
+ mAccessibilityManager.addAccessibilityStateChangeListener(listener);
+ ServiceControlUtils.enableMultipleFeedbackTypesService(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
+ "Accessibility state listener not called when services enabled");
+ assertTrue("Listener told that accessibility is enabled, but manager says disabled",
+ mAccessibilityManager.isEnabled());
+ ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
+ "Accessibility state listener not called when services disabled");
+ assertFalse("Listener told that accessibility is disabled, but manager says enabled",
+ mAccessibilityManager.isEnabled());
+ mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
+ }
+
+ private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
+ boolean expectedValue, Object waitObject, String message)
throws Exception {
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
synchronized (waitObject) {
- while (!listenerCalled.get() && (System.currentTimeMillis() < timeoutTime)) {
+ while ((atomicBoolean.get() != expectedValue)
+ && (System.currentTimeMillis() < timeoutTime)) {
waitObject.wait(timeoutTime - System.currentTimeMillis());
}
}
- assertTrue("Timed out waiting for listener called", listenerCalled.get());
+ assertTrue(message, atomicBoolean.get() == expectedValue);
}
private void waitForAccessibilityEnabled() throws InterruptedException {
@@ -295,7 +298,7 @@
AccessibilityStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
waitObject.notifyAll();
- }
+ }
};
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
@@ -308,25 +311,4 @@
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
}
-
- private void waitForTouchExplorationEnabled() throws InterruptedException {
- final Object waitObject = new Object();
-
- TouchExplorationStateChangeListener listener = (boolean b) -> {
- synchronized (waitObject) {
- waitObject.notifyAll();
- }
- };
- mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
- long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
- synchronized (waitObject) {
- while (!mAccessibilityManager.isTouchExplorationEnabled()
- && (System.currentTimeMillis() < timeoutTime)) {
- waitObject.wait(timeoutTime - System.currentTimeMillis());
- }
- }
- mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
- assertTrue("Timed out enabling touch exploration",
- mAccessibilityManager.isTouchExplorationEnabled());
- }
}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
index 9c4d9da..9783cb8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
@@ -165,10 +165,14 @@
* @param instrumentation A valid instrumentation
*/
public static void turnAccessibilityOff(Instrumentation instrumentation) {
- SpeakingAccessibilityService.sConnectedInstance.disableSelf();
- SpeakingAccessibilityService.sConnectedInstance = null;
- VibratingAccessibilityService.sConnectedInstance.disableSelf();
- VibratingAccessibilityService.sConnectedInstance = null;
+ if (SpeakingAccessibilityService.sConnectedInstance != null) {
+ SpeakingAccessibilityService.sConnectedInstance.disableSelf();
+ SpeakingAccessibilityService.sConnectedInstance = null;
+ }
+ if (VibratingAccessibilityService.sConnectedInstance != null) {
+ VibratingAccessibilityService.sConnectedInstance.disableSelf();
+ VibratingAccessibilityService.sConnectedInstance = null;
+ }
if (SpeakingAndVibratingAccessibilityService.sConnectedInstance != null) {
SpeakingAndVibratingAccessibilityService.sConnectedInstance.disableSelf();
SpeakingAndVibratingAccessibilityService.sConnectedInstance = null;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
index 23650a6..0f8b9c0 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -289,6 +289,8 @@
final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
.findAccessibilityNodeInfosByText(getString(stringId)).get(0);
CharSequence accessibilityTextWithSpan = text.getText();
+ // The span should work even with the node recycled
+ text.recycle();
assertTrue(accessibilityTextWithSpan instanceof Spanned);
T spans[] = ((Spanned) accessibilityTextWithSpan)
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 2ed4b39..8f9c51c 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -653,7 +653,7 @@
numPictureInPictureWindows++;
}
}
- assertEquals(1, numPictureInPictureWindows);
+ assertTrue(numPictureInPictureWindows >= 1);
}
private boolean isDividerWindowPresent(UiAutomation uiAutomation) {
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
index e0051a4..d60a1df 100644
--- a/tests/app/app/src/android/app/stubs/LocalForegroundService.java
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -45,9 +45,13 @@
private int mNotificationId = 0;
@Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
+ public void onCreate() {
+ super.onCreate();
+ Log.d(TAG, "service created: " + this + " in " + android.os.Process.myPid());
+ }
+ @Override
+ public void onStart(Intent intent, int startId) {
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(new NotificationChannel(
NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
@@ -56,6 +60,8 @@
Context context = getApplicationContext();
int command = intent.getIntExtra(EXTRA_COMMAND, -1);
+ Log.d(TAG, "service start cmd " + command + ", intent " + intent);
+
switch (command) {
case COMMAND_START_FOREGROUND:
mNotificationId ++;
@@ -89,11 +95,15 @@
default:
Log.e(TAG, "Unknown command: " + command);
}
+
+ // Do parent's onStart at the end, so we don't race with the test code waiting for us to
+ // execute.
+ super.onStart(intent, startId);
}
@Override
public void onDestroy() {
- Log.d(TAG, "service destroyed");
+ Log.d(TAG, "service destroyed: " + this + " in " + android.os.Process.myPid());
super.onDestroy();
}
diff --git a/tests/app/src/android/app/cts/ActionBarTest.java b/tests/app/src/android/app/cts/ActionBarTest.java
index 351339b..8bfaa59 100644
--- a/tests/app/src/android/app/cts/ActionBarTest.java
+++ b/tests/app/src/android/app/cts/ActionBarTest.java
@@ -24,7 +24,6 @@
import android.test.UiThreadTest;
import android.view.KeyEvent;
import android.view.Window;
-import org.junit.Assume;
public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
@@ -85,7 +84,9 @@
}
public void testOptionsMenuKey() {
- Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
+ if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+ return;
+ }
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/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/app/src/android/app/cts/ActivityOptionsTest.java
similarity index 61%
copy from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
copy to tests/app/src/android/app/cts/ActivityOptionsTest.java
index d599eba..eab44c5 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/app/src/android/app/cts/ActivityOptionsTest.java
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-package com.android.cts.webkit.renderprocesscrash;
+package android.app.cts;
-import android.app.Activity;
+import android.app.ActivityOptions;
import android.os.Bundle;
-import android.webkit.WebView;
+import android.test.AndroidTestCase;
-public class RenderProcessCrashActivity extends Activity {
+public class ActivityOptionsTest extends AndroidTestCase {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- WebView webView = new WebView(this);
- setContentView(webView);
- webView.loadUrl("chrome://kill");
+ public void testActivityOptionsBundle_makeBasic() throws Throwable {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ Bundle bundle = options.toBundle();
+
+ assertNotNull(bundle);
}
}
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/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 0e7b308..5f8202d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -574,12 +574,14 @@
boolean success = false;
try {
// Start service as foreground - it should show notification #1
+ Log.d(TAG, "Expecting first start state...");
mExpectedServiceState = STATE_START_1;
startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
waitForResultOrThrow(DELAY, "service to start first time");
assertNotification(1, LocalForegroundService.getNotificationTitle(1));
// Stop foreground removing notification
+ Log.d(TAG, "Expecting second start state...");
mExpectedServiceState = STATE_START_2;
if (usingFlags) {
startForegroundService(LocalForegroundService
@@ -730,7 +732,8 @@
boolean success = false;
PendingIntent pi = PendingIntent.getForegroundService(mContext, 1,
- foregroundServiceIntent(LocalForegroundService.COMMAND_START_FOREGROUND), 0);
+ foregroundServiceIntent(LocalForegroundService.COMMAND_START_FOREGROUND),
+ PendingIntent.FLAG_CANCEL_CURRENT);
TestSendCallback callback = new TestSendCallback();
try {
diff --git a/tests/app/src/android/app/cts/ToolbarActionBarTest.java b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
index d625802..46ab200 100644
--- a/tests/app/src/android/app/cts/ToolbarActionBarTest.java
+++ b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
@@ -21,7 +21,6 @@
import android.view.KeyEvent;
import android.view.Window;
-import org.junit.Assume;
public class ToolbarActionBarTest extends ActivityInstrumentationTestCase2<ToolbarActivity> {
@@ -40,7 +39,9 @@
}
public void testOptionsMenuKey() {
- Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
+ if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+ return;
+ }
final boolean menuIsVisible[] = {false};
mActivity.getActionBar().addOnMenuVisibilityListener(
isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java b/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
index 5094366..46dd551 100644
--- a/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
+++ b/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
@@ -164,7 +164,7 @@
}
@Override
- public void onBindingDead(ComponentName name) {
+ public void onBindingDied(ComponentName name) {
synchronized (this) {
// We want to remain connected to this service.
if (mMonitoring) {
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 663fe40..32bf5a5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -51,8 +51,10 @@
</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/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/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..b456dd7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -22,6 +22,7 @@
import static android.autofillservice.cts.Helper.getAutofillIds;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
+import android.autofillservice.cts.CannedFillResponse.Builder;
import android.content.IntentSender;
import android.os.Bundle;
import android.service.autofill.Dataset;
@@ -64,8 +65,10 @@
private final RemoteViews mPresentation;
private final IntentSender mAuthentication;
private final String[] mAuthenticationIds;
+ private final String[] mIgnoredIds;
private final CharSequence mNegativeActionLabel;
private final IntentSender mNegativeActionListener;
+ private final int mFlags;
private CannedFillResponse(Builder builder) {
mDatasets = builder.mDatasets;
@@ -77,8 +80,10 @@
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
mAuthenticationIds = builder.mAuthenticationIds;
+ mIgnoredIds = builder.mIgnoredIds;
mNegativeActionLabel = builder.mNegativeActionLabel;
mNegativeActionListener = builder.mNegativeActionListener;
+ mFlags = builder.mFlags;
}
/**
@@ -101,8 +106,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));
}
@@ -114,8 +128,11 @@
}
builder.setSaveInfo(saveInfo.build());
}
+ if (mIgnoredIds != null) {
+ builder.setIgnoredIds(getAutofillIds(structure, mIgnoredIds));
+ }
return builder
- .setExtras(mExtras)
+ .setClientState(mExtras)
.setAuthentication(getAutofillIds(structure, mAuthenticationIds), mAuthentication,
mPresentation)
.build();
@@ -126,10 +143,12 @@
return "CannedFillResponse: [datasets=" + mDatasets
+ ", requiredSavableIds=" + Arrays.toString(mRequiredSavableIds)
+ ", optionalSavableIds=" + Arrays.toString(mOptionalSavableIds)
+ + ", mFlags=" + mFlags
+ ", saveDescription=" + mSaveDescription
+ ", hasPresentation=" + (mPresentation != null)
+ ", hasAuthentication=" + (mAuthentication != null)
+ ", authenticationIds=" + Arrays.toString(mAuthenticationIds)
+ + ", ignoredIds=" + Arrays.toString(mIgnoredIds)
+ "]";
}
@@ -143,8 +162,10 @@
private RemoteViews mPresentation;
private IntentSender mAuthentication;
private String[] mAuthenticationIds;
+ private String[] mIgnoredIds;
private CharSequence mNegativeActionLabel;
private IntentSender mNegativeActionListener;
+ private int mFlags;
public Builder addDataset(CannedDataset dataset) {
mDatasets.add(dataset);
@@ -160,6 +181,11 @@
return this;
}
+ public Builder setFlags(int flags) {
+ mFlags = flags;
+ return this;
+ }
+
/**
* Sets the optional savable ids based on they {@code resourceId}.
*/
@@ -178,7 +204,7 @@
/**
* Sets the extra passed to {@link
- * android.service.autofill.FillResponse.Builder#setExtras(Bundle)}.
+ * android.service.autofill.FillResponse.Builder#setClientState(Bundle)}.
*/
public Builder setExtras(Bundle data) {
mExtras = data;
@@ -210,6 +236,14 @@
}
/**
+ * Sets the ignored fields based on resource ids.
+ */
+ public Builder setIgnoreFields(String...ids) {
+ mIgnoredIds = ids;
+ return this;
+ }
+
+ /**
* Sets the negative action spec.
*/
public Builder setNegativeAction(CharSequence label,
@@ -244,12 +278,14 @@
private final Map<String, RemoteViews> mFieldPresentations;
private final RemoteViews mPresentation;
private final IntentSender mAuthentication;
+ private final String mId;
private CannedDataset(Builder builder) {
mFieldValues = builder.mFieldValues;
mFieldPresentations = builder.mFieldPresentations;
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
+ mId = builder.mId;
}
/**
@@ -278,13 +314,13 @@
}
}
}
- builder.setAuthentication(mAuthentication);
+ builder.setId(mId).setAuthentication(mAuthentication);
return builder.build();
}
@Override
public String toString() {
- return "CannedDataset: [hasPresentation=" + (mPresentation != null)
+ return "CannedDataset " + mId + " : [hasPresentation=" + (mPresentation != null)
+ ", fieldPresentations=" + (mFieldPresentations)
+ ", hasAuthentication=" + (mAuthentication != null)
+ ", fieldValuess=" + mFieldValues + "]";
@@ -295,6 +331,7 @@
private final Map<String, RemoteViews> mFieldPresentations = new HashMap<>();
private RemoteViews mPresentation;
private IntentSender mAuthentication;
+ private String mId;
public Builder() {
@@ -365,6 +402,14 @@
return this;
}
+ /**
+ * Sets the name.
+ */
+ public Builder setId(String id) {
+ mId = id;
+ return this;
+ }
+
public CannedDataset build() {
return new CannedDataset(this);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
index 03be6a4..b04b45f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
@@ -28,6 +28,7 @@
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -64,6 +65,7 @@
private EditText mCcNumber;
private Spinner mCcExpiration;
+ private ArrayAdapter<CharSequence> mCcExpirationAdapter;
private RadioGroup mAddress;
private RadioButton mHomeAddress;
private CheckBox mSaveCc;
@@ -87,11 +89,11 @@
mBuyButton = (Button) findViewById(R.id.buy);
mClearButton = (Button) findViewById(R.id.clear);
- final ArrayAdapter<CharSequence> expirationValuesAdapter = createFromResource(this,
+ mCcExpirationAdapter = createFromResource(this,
R.array.cc_expiration_values, android.R.layout.simple_spinner_item);
- expirationValuesAdapter
+ mCcExpirationAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mCcExpiration.setAdapter(expirationValuesAdapter);
+ mCcExpiration.setAdapter(mCcExpirationAdapter);
mBuyButton.setOnClickListener((v) -> buy());
mClearButton.setOnClickListener((v) -> resetFields());
@@ -164,6 +166,13 @@
}
/**
+ * Visits the {@code ccExpirationDate} adapter in the UiThread.
+ */
+ void onCcExpirationAdapter(Visitor<ArrayAdapter<CharSequence>> v) {
+ syncRunOnUiThread(() -> v.visit(mCcExpirationAdapter));
+ }
+
+ /**
* Visits the {@code address} in the UiThread.
*/
void onAddress(Visitor<RadioGroup> v) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index 7289b5a..5a46c78 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -41,10 +41,7 @@
import android.autofillservice.cts.CannedFillResponse.CannedDataset;
import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.content.Context;
import android.support.test.rule.ActivityTestRule;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
@@ -54,8 +51,6 @@
import org.junit.Test;
import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Test case for an activity containing non-TextField views.
@@ -79,7 +74,7 @@
}
@Test
- public void testAutoFill() throws Exception {
+ public void testAutofill() throws Exception {
// Set service.
enableService();
@@ -103,11 +98,12 @@
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
- final String[] options = ccExpirationNode.getAutofillOptions();
+ final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
.containsExactly(
- getContext().getResources().getStringArray(R.array.cc_expiration_values));
+ getContext().getResources().getStringArray(R.array.cc_expiration_values))
+ .inOrder();
// Auto-fill it.
sUiBot.selectDataset("ACME CC");
@@ -117,7 +113,7 @@
}
@Test
- public void testAutoFillDynamicAdapter() throws Exception {
+ public void testAutofillDynamicAdapter() throws Exception {
// Set activity.
mActivity.onCcExpiration((v) -> v.setAdapter(new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
@@ -146,10 +142,8 @@
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
- final String[] options = ccExpirationNode.getAutofillOptions();
- assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
- assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
- .containsExactly("YESTERDAY", "TODAY", "TOMORROW", "NEVER");
+ final CharSequence[] options = ccExpirationNode.getAutofillOptions();
+ assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNull();
// Auto-fill it.
sUiBot.selectDataset("ACME CC");
@@ -161,26 +155,25 @@
// TODO(b/33197203): this should be a pure unit test exercising onProvideAutofillStructure(),
// but that would require creating a custom ViewStructure.
@Test
- public void testAutoFillDynamicAdapterWithNullItems() throws Exception {
- // Set activity.
- final MyAdapter adapter = new MyAdapter(getContext(),
- android.R.layout.simple_spinner_item,
- Arrays.asList("YESTERDAY", null, "TOMORROW", "NEVER"));
- mActivity.onCcExpiration((v) -> v.setAdapter(adapter));
-
+ public void testGetAutofillOptionsSorted() throws Exception {
// Set service.
enableService();
+ // Set activity.
+ mActivity.onCcExpirationAdapter((adapter) -> adapter.sort((a, b) -> {
+ return ((String) a).compareTo((String) b);
+ }));
+
// Set expectations.
- final int autoFilledIndex = 2; // NEVER
sReplier.addResponse(new CannedDataset.Builder()
.setPresentation(createPresentation("ACME CC"))
.setField(ID_CC_NUMBER, "4815162342")
- .setField(ID_CC_EXPIRATION, autoFilledIndex)
+ .setField(ID_CC_EXPIRATION, INDEX_CC_EXPIRATION_NEVER)
.setField(ID_ADDRESS, 1)
.setField(ID_SAVE_CC, true)
.build());
- mActivity.expectAutoFill("4815162342", autoFilledIndex, R.id.work_address, true);
+ mActivity.expectAutoFill("4815162342", INDEX_CC_EXPIRATION_NEVER, R.id.work_address,
+ true);
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
@@ -191,25 +184,20 @@
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
- final String[] options = ccExpirationNode.getAutofillOptions();
- assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
+ final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
- .containsExactly("YESTERDAY", "TOMORROW", "NEVER");
+ .containsExactly("never", "today", "tomorrow", "yesterday").inOrder();
// Auto-fill it.
sUiBot.selectDataset("ACME CC");
// Check the results.
mActivity.assertAutoFilled();
-
- // Make sure proper index was set.
- final AtomicInteger selected = new AtomicInteger();
- mActivity.onCcExpiration((v) -> selected.set(v.getSelectedItemPosition()));
- assertThat(selected.get()).isEqualTo(autoFilledIndex);
}
@Test
public void testSanitization() throws Exception {
+ // Set service.
enableService();
// Set expectations.
@@ -254,37 +242,4 @@
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_WORK_ADDRESS), true);
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_SAVE_CC), false);
}
-
- /**
- * Custom adapter used to change values after Spinner was rendered.
- */
- static class MyAdapter extends ArrayAdapter<String> {
-
- private final List<String> mList;
-
- public MyAdapter(Context context, int resource, List<String> objects) {
- super(context, resource, objects);
- mList = objects;
- }
-
- void setItem(int position, String value) {
- mList.set(position, value);
- }
-
- @Override
- public String getItem(int position) {
- return mList.get(position);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- // Hack: always return non-null item, otherwise Spinner.measure() will crash.
- for (int i = 0; i < mList.size(); i++) {
- if (mList.get(i) != null) {
- return super.getView(i, convertView, parent);
- }
- }
- return null;
- }
- }
}
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/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/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 db11ca1..ecfdb43 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -31,6 +31,10 @@
import static android.autofillservice.cts.LoginActivity.AUTHENTICATION_MESSAGE;
import static android.autofillservice.cts.LoginActivity.ID_USERNAME_CONTAINER;
import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
+import static android.service.autofill.FillEventHistory.Event.TYPE_AUTHENTICATION_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_AUTHENTICATION_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_SAVE_SHOWN;
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_EMAIL_ADDRESS;
@@ -39,7 +43,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;
@@ -57,6 +60,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.os.Bundle;
+import android.service.autofill.FillEventHistory;
import android.support.test.rule.ActivityTestRule;
import android.support.test.uiautomator.UiObject2;
import android.view.View;
@@ -64,6 +68,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;
@@ -789,6 +794,52 @@
// Set credentials...
mActivity.onUsername((v) -> v.setText("malkovich"));
+ mActivity.onPassword(View::requestFocus);
+ mActivity.onPassword((v) -> v.setText("malkovich"));
+
+ // ...and login
+ final String expectedMessage = getWelcomeMessage("malkovich");
+ final String actualMessage = mActivity.tapLogin();
+ assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+
+ // Assert the snack bar is shown and tap "Save".
+ sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+
+ // Assert value of expected fields - should not be sanitized.
+ final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME);
+ assertTextAndValue(username, "malkovich");
+ final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD);
+ assertTextAndValue(password, "malkovich");
+
+ // Sanity check: once saved, the session should be finsihed.
+ assertNoDanglingSessions();
+ }
+
+ @Test
+ public void testSaveOnlyOptionalField() throws Exception {
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME)
+ .setOptionalSavableIds(ID_PASSWORD)
+ .build());
+
+ // Trigger auto-fill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Sanity check.
+ sUiBot.assertNoDatasets();
+
+ // Wait for onFill() before proceeding, otherwise the fields might be changed before
+ // the session started
+ sReplier.getNextFillRequest();
+
+ // Set credentials...
+ mActivity.onUsername((v) -> v.setText("malkovich"));
+ mActivity.onPassword(View::requestFocus);
mActivity.onPassword((v) -> v.setText("malkovich"));
// ...and login
@@ -1097,53 +1148,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();
@@ -1251,14 +1267,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("");
@@ -1285,12 +1300,10 @@
mActivity.assertAutoFilled();
}
- @Test
public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
autofillManuallyTwoDatasets(true);
}
- @Test
public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
autofillManuallyTwoDatasets(false);
}
@@ -1301,7 +1314,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("");
@@ -1495,4 +1508,228 @@
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();
+ }
+
+ @Test
+ public void checkFillSelectionAfterSelectingDatasetAuthentication() throws Exception {
+ enableService();
+
+ // Set up FillResponse with dataset authentication
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ // Prepare the authenticated response
+ AuthenticationActivity.setDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dataset"))
+ .build());
+
+ IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), AuthenticationActivity.class), 0).getIntentSender();
+
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setId("name")
+ .setPresentation(createPresentation("authentication"))
+ .setAuthentication(authentication)
+ .build()).setExtras(clientState).build());
+
+ // Trigger autofill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Authenticate
+ sUiBot.selectDataset("authentication");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_DATASET_AUTHENTICATION_SELECTED);
+ assertThat(event.getDatasetId()).isEqualTo("name");
+ });
+ }
+
+ @Test
+ public void checkFillSelectionAfterSelectingAuthentication() throws Exception {
+ enableService();
+
+ // Set up FillResponse with response wide authentication
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ // Prepare the authenticated response
+ AuthenticationActivity.setResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setId("name")
+ .setPresentation(createPresentation("dataset"))
+ .build())
+ .setExtras(clientState).build());
+
+ IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), AuthenticationActivity.class), 0).getIntentSender();
+
+ sReplier.addResponse(new CannedFillResponse.Builder().setExtras(clientState)
+ .setPresentation(createPresentation("authentication"))
+ .setAuthentication(authentication)
+ .build());
+
+ // Trigger autofill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Authenticate
+ sUiBot.selectDataset("authentication");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_AUTHENTICATION_SELECTED);
+ assertThat(event.getDatasetId()).isNull();
+ });
+ }
+
+ @Test
+ public void checkFillSelectionAfterSelectingTwoDatasets() throws Exception {
+ enableService();
+
+ // Set up first partition with an anonymous dataset
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setPresentation(createPresentation("dataset1"))
+ .build())
+ .build());
+
+ // Trigger autofill on username
+ mActivity.onUsername(View::requestFocus);
+ sUiBot.selectDataset("dataset1");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState()).isNull();
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+ assertThat(event.getDatasetId()).isNull();
+ });
+
+ // Set up second partition with a named dataset
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_PASSWORD, "password2")
+ .setPresentation(createPresentation("dataset2"))
+ .setId("name2")
+ .build())
+ .addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_PASSWORD, "password3")
+ .setPresentation(createPresentation("dataset3"))
+ .setId("name3")
+ .build())
+ .setExtras(clientState)
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_PASSWORD).build());
+
+ // Trigger autofill on password
+ mActivity.onPassword(View::requestFocus);
+ sUiBot.selectDataset("dataset3");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+ assertThat(event.getDatasetId()).isEqualTo("name3");
+ });
+
+ mActivity.onPassword((v) -> v.setText("new password"));
+ mActivity.syncRunOnUiThread(() -> mActivity.finish());
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(2);
+ FillEventHistory.Event event1 = selection.getEvents().get(0);
+ assertThat(event1.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+ assertThat(event1.getDatasetId()).isEqualTo("name3");
+
+ FillEventHistory.Event event2 = selection.getEvents().get(1);
+ assertThat(event2.getType()).isEqualTo(TYPE_SAVE_SHOWN);
+ assertThat(event2.getDatasetId()).isNull();
+ });
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
index c2af4cc1..32844d4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
@@ -49,25 +49,24 @@
setContentView(R.layout.single_button_activity);
findViewById(R.id.button).setOnClickListener((v) -> {
- // We should get the assist structure
AssistStructure structure = getIntent().getParcelableExtra(
AutofillManager.EXTRA_ASSIST_STRUCTURE);
- assertWithMessage("structure not called").that(structure).isNotNull();
+ 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");
+ }
- Parcelable result = null;
- 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);
}
- // 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/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index 49ddf8f..b3902b3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -599,6 +599,41 @@
assertValue(saveRequest.structure, ID_L4C1, "L4C1");
}
+ @Test
+ public void testIgnoredFieldsDontTriggerAutofill() throws Exception {
+ // Set service.
+ enableService();
+
+ // Prepare 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())
+ .setIgnoreFields(ID_L2C1, ID_L2C2)
+ .build();
+ sReplier.addResponse(response1);
+
+ // Trigger auto-fill on 1st partition.
+ mActivity.focusCell(1, 1);
+ final FillRequest fillRequest1 = sReplier.getNextFillRequest();
+ final ViewNode p1l1c1 = assertTextIsSanitized(fillRequest1.structure, ID_L1C1);
+ final ViewNode p1l1c2 = assertTextIsSanitized(fillRequest1.structure, ID_L1C2);
+ assertWithMessage("Focus on p1l1c1").that(p1l1c1.isFocused()).isTrue();
+ assertWithMessage("Focus on p1l1c2").that(p1l1c2.isFocused()).isFalse();
+
+ // Make sure UI is shown on 1st partition
+ sUiBot.assertDatasets("l1c1");
+ mActivity.focusCell(1, 2);
+ sUiBot.assertDatasets("l1c2");
+
+ // Make sure UI is not shown on ignored partition
+ mActivity.focusCell(2, 1);
+ sUiBot.assertNoDatasets();
+ mActivity.focusCell(2, 2);
+ sUiBot.assertNoDatasets();
+ }
+
// TODO(b/33197203, b/35707731): test force autofill after autofilled
// TODO(b/33197203, b/35707731): test save with different subtitles and custom no button
}
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
index a5f74c5..0454277 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -174,8 +174,6 @@
// Login
sUiBot.selectById(LOGIN_FULL_ID);
- /* TODO: b/37117412
-
// Wait for save UI to be shown
sUiBot.assertShownById("android:id/autofill_save_yes");
@@ -202,8 +200,6 @@
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/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 1f98171..deba8b7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -92,7 +92,7 @@
// not showing...
return;
}
- throw new AssertionError("floating ui is shown: " + ui);
+ throw new RetryableException("floating ui is shown: %s", ui);
}
/**
@@ -202,6 +202,13 @@
}
/**
+ * Presses the back button.
+ */
+ void pressBack() {
+ mDevice.pressBack();
+ }
+
+ /**
* Asserts the save snackbar is not showing and returns it.
*/
void assertSaveNotShowing(int type) {
@@ -212,7 +219,7 @@
// 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");
}
private String getSaveTypeString(int type) {
@@ -328,7 +335,7 @@
}
menuNames.append("'").append(menuName).append("' ");
}
- throw new AssertionError("no '" + expectedText + "' on " + menuNames);
+ throw new RetryableException("no '%s' on '%s'", expectedText, menuNames);
}
/**
@@ -375,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);
}
/**
@@ -405,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));
@@ -429,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..e4ca5af 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"
diff --git a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
index b5e9cad..dba0c07 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -28,14 +28,13 @@
import android.app.FragmentController;
import android.app.FragmentManager;
import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
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;
import android.util.Pair;
import android.view.View;
+import android.view.animation.TranslateAnimation;
import org.junit.Before;
import org.junit.Rule;
@@ -59,11 +58,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);
}
@@ -105,8 +101,9 @@
}
// Ensure that showing and popping a Fragment uses the enter and popExit animators
+ // This tests optimized transactions
@Test
- public void showAnimators() throws Throwable {
+ public void showAnimatorsOptimized() throws Throwable {
final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
// One fragment with a view
@@ -114,6 +111,10 @@
fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
FragmentTestUtil.waitForExecution(mActivityRule);
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
+
fm.beginTransaction()
.setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
.show(fragment)
@@ -121,7 +122,51 @@
.commit();
FragmentTestUtil.waitForExecution(mActivityRule);
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+ });
assertEnterPopExit(fragment);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
+ }
+
+ // Ensure that showing and popping a Fragment uses the enter and popExit animators
+ // This tests unoptimized transactions
+ @Test
+ public void showAnimatorsUnoptimized() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+ // One fragment with a view
+ final AnimatorFragment fragment = new AnimatorFragment();
+ fm.beginTransaction()
+ .add(R.id.fragmentContainer, fragment)
+ .hide(fragment)
+ .setAllowOptimization(false)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
+
+ fm.beginTransaction()
+ .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+ .show(fragment)
+ .setAllowOptimization(false)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+ });
+ assertEnterPopExit(fragment);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
}
// Ensure that hiding and popping a Fragment uses the exit and popEnter animators
@@ -365,12 +410,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());
@@ -391,6 +436,68 @@
assertNotNull(fragment1restored.getView());
}
+ // When an animation is running on a Fragment's View, the view shouldn't be
+ // prevented from being removed. There's no way to directly test this, so we have to
+ // test to see if the animation is still running.
+ @Test
+ public void clearAnimations() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+ final StrictViewFragment fragment1 = new StrictViewFragment();
+ fm.beginTransaction()
+ .add(R.id.fragmentContainer, fragment1)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ final View fragmentView = fragment1.getView();
+
+ final TranslateAnimation xAnimation = new TranslateAnimation(0, 1000, 0, 0);
+ xAnimation.setDuration(10000);
+ mActivityRule.runOnUiThread(() -> {
+ fragmentView.startAnimation(xAnimation);
+ assertEquals(xAnimation, fragmentView.getAnimation());
+ });
+
+ FragmentTestUtil.waitForExecution(mActivityRule);
+ FragmentTestUtil.popBackStackImmediate(mActivityRule);
+ mActivityRule.runOnUiThread(() -> {
+ assertNull(fragmentView.getAnimation());
+ });
+ }
+
+ /**
+ * When a fragment container is null, you shouldn't see an NPE even with an animation.
+ */
+ @Test
+ public void animationOnNullContainer() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+ // One fragment with a view
+ final AnimatorFragment fragment = new AnimatorFragment();
+ fm.beginTransaction()
+ .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+ .add(fragment, "1")
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ fm.beginTransaction()
+ .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+ .hide(fragment)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ fm.beginTransaction()
+ .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+ .show(fragment)
+ .commit();
+
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ FragmentTestUtil.popBackStackImmediate(mActivityRule);
+ }
+
private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
assertFragmentAnimation(fragment, 1, true, ENTER);
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/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index ebda7a2..abf7fd8 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -870,6 +870,45 @@
});
}
+ /**
+ * When the FragmentManager state changes, the pending transactions should execute.
+ */
+ @Test
+ public void runTransactionsOnChange() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, null);
+ FragmentManager fm = fc.getFragmentManager();
+
+ RemoveHelloInOnResume fragment1 = new RemoveHelloInOnResume();
+ StrictFragment fragment2 = new StrictFragment();
+ fm.beginTransaction()
+ .add(fragment1, "1")
+ .setAllowOptimization(false)
+ .commit();
+ fm.beginTransaction()
+ .add(fragment2, "Hello")
+ .setAllowOptimization(false)
+ .commit();
+ fm.executePendingTransactions();
+
+ assertEquals(2, fm.getFragments().size());
+ assertTrue(fm.getFragments().contains(fragment1));
+ assertTrue(fm.getFragments().contains(fragment2));
+
+ Pair<Parcelable, FragmentManagerNonConfig> savedState =
+ FragmentTestUtil.destroy(mActivityRule, fc);
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, savedState);
+ fm = fc.getFragmentManager();
+
+ assertEquals(1, fm.getFragments().size());
+ for (Fragment fragment : fm.getFragments()) {
+ assertTrue(fragment instanceof RemoveHelloInOnResume);
+ }
+ });
+ }
+
private void executePendingTransactions(final FragmentManager fm) throws Throwable {
mActivityRule.runOnUiThread(new Runnable() {
@Override
@@ -1065,4 +1104,15 @@
return mValue;
}
}
+
+ public static class RemoveHelloInOnResume extends Fragment {
+ @Override
+ public void onResume() {
+ super.onResume();
+ Fragment fragment = getFragmentManager().findFragmentByTag("Hello");
+ if (fragment != null) {
+ getFragmentManager().beginTransaction().remove(fragment).commit();
+ }
+ }
+ }
}
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/FragmentTransactionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
index aec30c1..7deea1b 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
@@ -20,6 +20,10 @@
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -354,6 +358,51 @@
}
}
+ @Test
+ public void testGetLayoutInflater() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ final OnGetLayoutInflaterFragment fragment1 = new OnGetLayoutInflaterFragment();
+ assertEquals(0, fragment1.onGetLayoutInflaterCalls);
+ mActivity.getFragmentManager().beginTransaction()
+ .add(android.R.id.content, fragment1)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+ assertEquals(fragment1.layoutInflater, fragment1.getLayoutInflater());
+ // getLayoutInflater() didn't force onGetLayoutInflater()
+ assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+
+ LayoutInflater layoutInflater = fragment1.layoutInflater;
+ // Replacing fragment1 won't detach it, so the value won't be cleared
+ final OnGetLayoutInflaterFragment fragment2 = new OnGetLayoutInflaterFragment();
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, fragment2)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+
+ assertSame(layoutInflater, fragment1.getLayoutInflater());
+ assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+
+ // Popping it should cause onCreateView again, so a new LayoutInflater...
+ mActivity.getFragmentManager().popBackStackImmediate();
+ assertNotSame(layoutInflater, fragment1.getLayoutInflater());
+ assertEquals(2, fragment1.onGetLayoutInflaterCalls);
+ layoutInflater = fragment1.layoutInflater;
+ assertSame(layoutInflater, fragment1.getLayoutInflater());
+
+ // Popping it should detach it, clearing the cached value again
+ mActivity.getFragmentManager().popBackStackImmediate();
+
+ // once it is detached, the getLayoutInflater() will default to throw
+ // an exception, but we've made it return null instead.
+ assertEquals(2, fragment1.onGetLayoutInflaterCalls);
+ assertNull(fragment1.getLayoutInflater());
+ assertEquals(3, fragment1.onGetLayoutInflaterCalls);
+ });
+ }
+
private void getFragmentsUntilSize(int expectedSize) {
final long endTime = SystemClock.uptimeMillis() + 3000;
@@ -377,4 +426,26 @@
return inflater.inflate(R.layout.text_a, container, false);
}
}
+
+ public static class OnGetLayoutInflaterFragment extends Fragment {
+ public int onGetLayoutInflaterCalls = 0;
+ public LayoutInflater layoutInflater;
+
+ @Override
+ public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
+ onGetLayoutInflaterCalls++;
+ try {
+ layoutInflater = super.onGetLayoutInflater(savedInstanceState);
+ } catch (Exception e) {
+ return null;
+ }
+ return layoutInflater;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.text_a, container, false);
+ }
+ }
}
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/jni/android_hardware_cts_SensorNativeTest.cpp b/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
index 40a5ff7..4c8b323 100644
--- a/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
+++ b/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
@@ -54,7 +54,7 @@
std::vector<int32_t> rates = {
ASENSOR_DIRECT_RATE_NORMAL, ASENSOR_DIRECT_RATE_FAST, ASENSOR_DIRECT_RATE_VERY_FAST};
std::vector<int32_t> channelTypes =
- {ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY};
+ {ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER};
for (auto s : sensorTypes) {
for (auto c : channelTypes) {
for (auto r : rates) {
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/appwidget/src/android/appwidget/cts/AppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
index a017b6c..747a8bd 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
@@ -174,6 +174,38 @@
}
}
+ public void testGetAppWidgetIdsForHost() throws Exception {
+ if (!hasAppWidgets()) {
+ return;
+ }
+ AppWidgetHost host1 = new AppWidgetHost(getInstrumentation().getTargetContext(), 1);
+ AppWidgetHost host2 = new AppWidgetHost(getInstrumentation().getTargetContext(), 2);
+
+ host1.deleteHost();
+ host2.deleteHost();
+
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+ int id1 = host1.allocateAppWidgetId();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+ int id2 = host1.allocateAppWidgetId();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1, id2}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+ int id3 = host2.allocateAppWidgetId();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1, id2}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{id3}));
+
+ host1.deleteHost();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{id3}));
+
+ host2.deleteHost();
+ }
+
public void testAppWidgetProviderCallbacks() throws Exception {
if (!hasAppWidgets()) {
return;
@@ -380,7 +412,7 @@
}
}
- public void testGetAppWidgetIds() throws Exception {
+ public void testGetAppWidgetIdsForProvider() throws Exception {
if (!hasAppWidgets()) {
return;
}
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/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/ClipDescriptionTest.java b/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java
index a69a3f8..bd9756e 100644
--- a/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java
+++ b/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java
@@ -21,7 +21,6 @@
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
-import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
@@ -30,6 +29,12 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Calendar;
+
+/**
+ * To run:
+ * cts-tradefed run singleCommand cts-dev -m CtsContentTestCases -t android.content.cts.ClipDescriptionTest
+ */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ClipDescriptionTest {
@@ -37,17 +42,35 @@
@Test
public void testGetTimestamp() {
final ClipboardManager clipboardManager = (ClipboardManager)
- InstrumentationRegistry.getTargetContext().getSystemService(Context.CLIPBOARD_SERVICE);
- final long timestampBeforeSet = SystemClock.elapsedRealtime();
+ InstrumentationRegistry.getTargetContext().getSystemService(
+ Context.CLIPBOARD_SERVICE);
+ final long timestampBeforeSet = System.currentTimeMillis();
clipboardManager.setPrimaryClip(ClipData.newPlainText("Dummy text", "Text"));
- final long timestampAfterSet = SystemClock.elapsedRealtime();
+ final long timestampAfterSet = System.currentTimeMillis();
final long timestamp = clipboardManager.getPrimaryClipDescription().getTimestamp();
if (timestamp < timestampBeforeSet || timestamp > timestampAfterSet) {
fail("Value of timestamp is not as expected.\n"
- + "timestamp before setting clip: " + timestampBeforeSet + "\n"
- + "timestamp after setting clip: " + timestampAfterSet + "\n"
- + "actual timestamp: " + timestamp
+ + "timestamp before setting clip: " + logTime(timestampBeforeSet) + "\n"
+ + "timestamp after setting clip: " + logTime(timestampAfterSet) + "\n"
+ + "actual timestamp: " + logTime(timestamp) + "\n"
+ "clipdata: " + clipboardManager.getPrimaryClip());
}
}
+
+ /**
+ * Convert a System.currentTimeMillis() value to a time of day value like
+ * that printed in logs. MM-DD-YY HH:MM:SS.MMM
+ *
+ * @param millis since the epoch (1/1/1970)
+ * @return String representation of the time.
+ */
+ public static String logTime(long millis) {
+ Calendar c = Calendar.getInstance();
+ if (millis >= 0) {
+ c.setTimeInMillis(millis);
+ return String.format("%tm-%td-%ty %tH:%tM:%tS.%tL", c, c, c, c, c, c, c);
+ } else {
+ return Long.toString(millis);
+ }
+ }
}
\ No newline at end of file
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/content/src/android/content/pm/cts/ComponentInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
index 5137d8a..c937e2a 100644
--- a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
@@ -20,11 +20,11 @@
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.test.AndroidTestCase;
-import android.util.LauncherIcons;
import android.util.Printer;
import android.util.StringBuilderPrinter;
@@ -68,9 +68,15 @@
}
}
- public void testLoadIcon() {
+ private Bitmap createIconBitmap(Drawable d) {
+ int size = Math.round(100 * getContext().getResources().getDisplayMetrics().density) + 100;
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ d.setBounds(0, 0, size, size);
+ d.draw(new Canvas(bitmap));
+ return bitmap;
+ }
- LauncherIcons launcherIcons = new LauncherIcons(getContext());
+ public void testLoadIcon() {
mComponentInfo = new ComponentInfo();
mComponentInfo.applicationInfo = new ApplicationInfo();
@@ -83,14 +89,12 @@
d = mComponentInfo.loadIcon(pm);
assertNotNull(d);
assertNotSame(d, defaultIcon);
- WidgetTestUtils.assertEquals(launcherIcons.createIconBitmap(d),
- launcherIcons.createIconBitmap(defaultIcon));
+ WidgetTestUtils.assertEquals(createIconBitmap(d), createIconBitmap(defaultIcon));
d2 = mComponentInfo.loadIcon(pm);
assertNotNull(d2);
assertNotSame(d, d2);
- WidgetTestUtils.assertEquals(launcherIcons.createIconBitmap(d),
- launcherIcons.createIconBitmap(d2));
+ WidgetTestUtils.assertEquals(createIconBitmap(d), createIconBitmap(d2));
try {
mComponentInfo.loadIcon(null);
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/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 5012e1c..a296659 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
@@ -38,6 +38,7 @@
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;
@@ -61,13 +62,14 @@
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, null);
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
- assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+ assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true,
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
@@ -75,7 +77,7 @@
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
- b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true, null);
+ 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);
@@ -86,38 +88,43 @@
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
- b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true, null);
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
- assertSame(ColorSpace.get(ColorSpace.Named.SRGB), 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(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+ assertSame(sRGB, cs);
- b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, null);
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
- assertSame(ColorSpace.get(ColorSpace.Named.SRGB), 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(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+ assertSame(sRGB, cs);
- b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true, null);
+ b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
- assertSame(ColorSpace.get(ColorSpace.Named.SRGB), 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(ColorSpace.get(ColorSpace.Named.SRGB), 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)
@@ -520,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;
@@ -552,6 +575,99 @@
}
@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);
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..2d42f3c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -26,12 +26,15 @@
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.cts.R;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.InsetDrawable;
import android.support.test.InstrumentationRegistry;
@@ -141,9 +144,42 @@
}
@Test
- public void testGetPadding() {
+ public void testGetPadding_dimension() {
InsetDrawable insetDrawable = new InsetDrawable(mPassDrawable, 1, 2, 3, 4);
+ Rect r = new Rect();
+ assertEquals(0, r.left);
+ assertEquals(0, r.top);
+ assertEquals(0, r.right);
+ assertEquals(0, r.bottom);
+ assertTrue(insetDrawable.getPadding(r));
+
+ assertEquals(1, r.left);
+ assertEquals(2, r.top);
+ assertEquals(3, r.right);
+ assertEquals(4, r.bottom);
+
+ // padding is set to 0, then return value should be false
+ insetDrawable = new InsetDrawable(mPassDrawable, .0f);
+
+ r = new Rect();
+ assertEquals(0, r.left);
+ assertEquals(0, r.top);
+ assertEquals(0, r.right);
+ assertEquals(0, r.bottom);
+
+ assertFalse(insetDrawable.getPadding(r));
+
+ assertEquals(0, r.left);
+ assertEquals(0, r.top);
+ assertEquals(0, r.right);
+ assertEquals(0, r.bottom);
+ }
+
+ @Test
+ public void testGetPadding_fraction() {
+ InsetDrawable insetDrawable = new InsetDrawable(mPassDrawable, .1f, .2f, .3f, .4f);
+ insetDrawable.setBounds(0, 0, 10, 10);
Rect r = new Rect();
assertEquals(0, r.left);
assertEquals(0, r.top);
@@ -242,7 +278,7 @@
}
@Test
- public void testOnBoundsChange() {
+ public void testOnBoundsChange_dimension() {
MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 5);
Rect bounds = mPassDrawable.getBounds();
@@ -260,6 +296,56 @@
assertEquals(-5, bounds.bottom);
}
+ @Test
+ public void testOnBoundsChange_fraction() {
+ float inset = .1f;
+ int size = 40;
+ MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 0.1f);
+
+ Rect bounds = mPassDrawable.getBounds();
+ assertEquals(0, bounds.left);
+ assertEquals(0, bounds.top);
+ assertEquals(0, bounds.right);
+ assertEquals(0, bounds.bottom);
+
+ Rect r = new Rect(0, 0, size, size);
+ insetDrawable.onBoundsChange(r);
+
+ assertEquals((int) (size * inset), bounds.left);
+ assertEquals((int) (size * inset), bounds.top);
+ assertEquals(size - (int) (size * inset), bounds.right);
+ assertEquals(size - (int) (size * inset), bounds.bottom);
+ }
+
+ @Test
+ public void testIsBoundsAndIntrinsicSizeInverse() {
+ float inset = .1f;
+
+ // Test that intrinsic Width and Height calculation logic is inverse of the onBoundsChange.
+ MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, inset);
+
+ assertEquals((int)(mPassDrawable.getIntrinsicWidth() / (1 - 2 * inset)),
+ insetDrawable.getIntrinsicWidth());
+ assertEquals((int)(mPassDrawable.getIntrinsicHeight() / (1 - 2 * inset)),
+ insetDrawable.getIntrinsicHeight());
+
+ Rect r = new Rect(0, 0, insetDrawable.getIntrinsicWidth(),
+ insetDrawable.getIntrinsicHeight());
+ insetDrawable.onBoundsChange(r);
+ r = mPassDrawable.getBounds();
+
+ assertEquals((int)(insetDrawable.getIntrinsicWidth() * inset), r.left);
+ assertEquals((int)(insetDrawable.getIntrinsicHeight() * inset), r.top);
+ assertEquals(insetDrawable.getIntrinsicWidth()
+ - (int)((inset) * insetDrawable.getIntrinsicWidth()), r.right);
+ assertEquals(insetDrawable.getIntrinsicHeight()
+ - (int)((inset) * insetDrawable.getIntrinsicHeight()), r.bottom);
+
+ // Verify inverse!!
+ assertEquals(r.width(), mPassDrawable.getIntrinsicWidth(), 1);
+ assertEquals(r.height(), mPassDrawable.getIntrinsicHeight(), 1);
+ }
+
@Test(expected=NullPointerException.class)
public void testOnBoundsChangeNull() {
MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 5);
@@ -287,6 +373,10 @@
mPassDrawable = mContext.getDrawable(R.drawable.inset_color);
expected = -1;
assertEquals(expected, mPassDrawable.getIntrinsicWidth());
+
+ mInsetDrawable = new InsetDrawable(mPassDrawable, .2f);
+ expected = (int)(mPassDrawable.getIntrinsicWidth() * (1.4f));
+ assertEquals(expected, mInsetDrawable.getIntrinsicWidth());
}
@Test
@@ -309,6 +399,10 @@
mPassDrawable = mContext.getDrawable(R.drawable.inset_color);
expected = -1;
assertEquals(expected, mPassDrawable.getIntrinsicHeight());
+
+ mInsetDrawable = new InsetDrawable(mPassDrawable, .2f);
+ expected = (int)(mPassDrawable.getIntrinsicHeight() * (1.4f));
+ assertEquals(expected, mInsetDrawable.getIntrinsicHeight());
}
@Test
@@ -342,12 +436,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 +466,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,14 +493,20 @@
// 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());
}
private class MockInsetDrawable extends InsetDrawable {
+ public MockInsetDrawable(Drawable drawable, float inset) {
+ super(drawable, inset);
+ }
+
public MockInsetDrawable(Drawable drawable, int inset) {
super(drawable, inset);
}
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..4721afb 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -71,11 +71,21 @@
}
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 wrong_arch(const std::string& err) {
+ // https://issuetracker.google.com/37428428
+ // It's okay to not be able to load a library because it's for another
+ // architecture (typically on an x86 device, when we come across an arm library).
+ return err.find("unexpected e_machine: ") != std::string::npos;
}
static bool check_lib(const std::string& path,
@@ -104,7 +114,7 @@
} else { // (handle == nullptr && !shouldBeAccessible(path))
// Check the error message
std::string err = dlerror();
- if (!already_loaded(path, err)) {
+ if (!already_loaded(path, err) && !wrong_arch(err)) {
errors->push_back("unexpected dlerror: " + err);
return false;
}
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 bec6350..3e291cf 100644
--- a/tests/tests/location/src/android/location/cts/LocationTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationTest.java
@@ -282,10 +282,6 @@
location.setVerticalAccuracyMeters(1.0f);
assertEquals(1.0, location.getVerticalAccuracyMeters(), DELTA);
assertTrue(location.hasVerticalAccuracy());
-
- location.removeVerticalAccuracy();
- assertEquals(0.0, location.getVerticalAccuracyMeters(), DELTA);
- assertFalse(location.hasVerticalAccuracy());
}
public void testAccessSpeedAccuracy() {
@@ -295,10 +291,6 @@
location.setSpeedAccuracyMetersPerSecond(1.0f);
assertEquals(1.0, location.getSpeedAccuracyMetersPerSecond(), DELTA);
assertTrue(location.hasSpeedAccuracy());
-
- location.removeSpeedAccuracy();
- assertEquals(0.0, location.getSpeedAccuracyMetersPerSecond(), DELTA);
- assertFalse(location.hasSpeedAccuracy());
}
public void testAccessBearingAccuracy() {
@@ -308,10 +300,6 @@
location.setBearingAccuracyDegrees(1.0f);
assertEquals(1.0, location.getBearingAccuracyDegrees(), DELTA);
assertTrue(location.hasBearingAccuracy());
-
- location.removeBearingAccuracy();
- assertEquals(0.0, location.getBearingAccuracyDegrees(), DELTA);
- assertFalse(location.hasBearingAccuracy());
}
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index 1a3a2f0..891fa11 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -181,9 +181,9 @@
int state = measurement.getState();
softAssert.assertTrue("state: Satellite code sync state",
timeInNs,
- "X > 0",
+ "X >= 0",
String.valueOf(state),
- state >=0);
+ state >= 0);
// Check received_gps_tow_uncertainty_ns
softAssert.assertTrueAsWarning("received_gps_tow_uncertainty_ns:" +
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..2bf24b6 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -102,6 +103,13 @@
}
public void testSetOnVolumeKeyLongPressListener() throws Exception {
+ Context context = getInstrumentation().getTargetContext();
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ // Skip this test on TV platform because the PhoneWindowManager dispatches volume key
+ // events directly to the audio service to change the system volume.
+ return;
+ }
+
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
@@ -149,6 +157,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..58a643d 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);
@@ -409,6 +390,26 @@
}
}
+ /**
+ * Test {@link MediaSession#release} doesn't crash when multiple media sessions are in the app
+ * which receives the media key events.
+ * See: b/36669550
+ */
+ public void testReleaseNoCrashWithMultipleSessions() throws Exception {
+ // Start a media playback for this app to receive media key events.
+ Utils.assertMediaPlaybackStarted(getContext());
+
+ MediaSession anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+ mSession.release();
+ anotherSession.release();
+
+ // Try release with the different order.
+ mSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+ anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+ anotherSession.release();
+ mSession.release();
+ }
+
private void simulateMediaKeyInput(int keyCode) {
mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
@@ -474,8 +475,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 +483,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 +493,6 @@
mOnAudioInfoChangedCalled = false;
mOnSessionDestroyedCalled = false;
mOnSessionEventCalled = false;
- mOnRepeatModeChangedCalled = false;
- mOnShuffleModeChangedCalled = false;
mPlaybackState = null;
mMediaMetadata = null;
@@ -505,8 +500,6 @@
mTitle = null;
mExtras = null;
mPlaybackInfo = null;
- mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
- mShuffleModeEnabled = false;
}
@Override
@@ -580,24 +573,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 628a50b..e22d8a7 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -333,7 +333,7 @@
}
// TODO: unhide this test when we sort out how to expose buffering control API.
- private void testBuffering() throws Throwable {
+ 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..8599d48
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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(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..bcecee1 100644
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
@@ -21,11 +21,13 @@
import android.net.IpSecAlgorithm;
import android.net.IpSecManager;
import android.net.IpSecTransform;
+import android.os.ParcelFileDescriptor;
+import android.system.Os;
+import android.system.OsConstants;
import android.test.AndroidTestCase;
-import android.util.Log;
-import java.io.IOException;
-import java.net.DatagramPacket;
+import java.io.ByteArrayOutputStream;
import java.net.DatagramSocket;
+import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
@@ -82,17 +84,17 @@
public void testAllocSpi() throws Exception {
for (InetAddress addr : GOOGLE_DNS_LIST) {
IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
- randomSpi =
- mISM.reserveSecurityParameterIndex(
- IpSecTransform.DIRECTION_OUT,
- addr,
- IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
- assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+ randomSpi = mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, addr);
+ assertTrue(
+ "Failed to receive a valid SPI",
+ randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
droidSpi =
mISM.reserveSecurityParameterIndex(
IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
- assertTrue(droidSpi.getSpi() == DROID_SPI);
+ assertTrue(
+ "Failed to allocate specified SPI, " + DROID_SPI,
+ droidSpi.getSpi() == DROID_SPI);
try {
mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
@@ -119,10 +121,7 @@
public void testCreateTransform() throws Exception {
InetAddress local = InetAddress.getLoopbackAddress();
IpSecManager.SecurityParameterIndex outSpi =
- mISM.reserveSecurityParameterIndex(
- IpSecTransform.DIRECTION_OUT,
- local,
- IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+ mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, local);
IpSecManager.SecurityParameterIndex inSpi =
mISM.reserveSecurityParameterIndex(
@@ -133,46 +132,40 @@
.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);
- DatagramSocket localSocket;
- localSocket = new DatagramSocket(8888);
-
+ // Hack to ensure the socket doesn't block indefinitely on failure
+ DatagramSocket localSocket = new DatagramSocket(8888);
localSocket.setSoTimeout(500);
- mISM.applyTransportModeTransform(localSocket, transform);
+ ParcelFileDescriptor pin = ParcelFileDescriptor.fromDatagramSocket(localSocket);
+ FileDescriptor udpSocket = pin.getFileDescriptor();
+
+ mISM.applyTransportModeTransform(udpSocket, transform);
byte[] data = new String("Best test data ever!").getBytes("UTF-8");
- DatagramPacket out = new DatagramPacket(data, data.length, local, 8888);
- localSocket.send(out);
- DatagramPacket in = new DatagramPacket(new byte[data.length], data.length);
-
- localSocket.receive(in);
- Log.d(TAG, Arrays.toString(data));
- Log.d(TAG, Arrays.toString(in.getData()));
- assertTrue(Arrays.equals(data, in.getData()));
+ byte[] in = new byte[data.length];
+ Os.sendto(udpSocket, data, 0, data.length, 0, local, 8888);
+ Os.read(udpSocket, in, 0, in.length);
+ assertTrue("Encapsulated data did not match.", Arrays.equals(data, in));
+ mISM.removeTransportModeTransform(udpSocket, transform);
+ Os.close(udpSocket);
transform.close();
- try {
- localSocket.send(out);
- } catch (IOException e) {
- }
-
- mISM.removeTransportModeTransform(localSocket, transform);
}
}
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/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 4e6b9ea..8f0de7f 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -37,6 +37,7 @@
<protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
@@ -284,6 +285,7 @@
<protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
<protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
@@ -491,7 +493,9 @@
<protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
<protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ <protected-broadcast android:name="android.accounts.action.ACCOUNT_REMOVED" />
<protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
+
<protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
<protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
@@ -528,9 +532,14 @@
<protected-broadcast android:name="com.android.internal.autofill.action.REQUEST_AUTOFILL" />
<protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED" />
<protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
<protected-broadcast android:name="android.os.action.USER_RESTRICTIONS_CHANGED" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -803,7 +812,7 @@
<p>Protection level: dangerous-->
<permission android:name="android.permission.READ_PHONE_NUMBERS"
android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readPhoneNumber"
+ android:label="@string/permlab_readPhoneNumbers"
android:description="@string/permdesc_readPhoneNumbers"
android:protectionLevel="dangerous|ephemeral" />
@@ -1299,6 +1308,13 @@
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
android:protectionLevel="signature|setup" />
+ <!-- Allows network stack services (Connectivity and Wifi) to coordinate
+ <p>Not for use by third-party or privileged applications.
+ @hide This should only be used by Connectivity and Wifi Services.
+ -->
+ <permission android:name="android.permission.NETWORK_STACK"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -1511,6 +1527,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"
@@ -1644,6 +1670,21 @@
<permission android:name="android.permission.BIND_IMS_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
+ EuiccManager APIs.
+ <p>Protection level: signature|privileged|development
+ TODO(b/35851809): Mark this as a SystemApi.
+ @hide -->
+ <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Must be required by an EuiccService to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ TODO(b/35851809): Mark this as a SystemApi.
+ @hide -->
+ <permission android:name="android.permission.BIND_EUICC_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
@@ -1851,6 +1892,11 @@
android:description="@string/permdesc_useDataInBackground"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to set display offsets for the screen.
+ This permission is not available to third party applications. -->
+ <permission android:name="android.permission.SET_DISPLAY_OFFSET"
+ android:protectionLevel="signature|privileged" />
+
<!-- ================================== -->
<!-- Permissions affecting the system wallpaper -->
<!-- ================================== -->
@@ -2511,6 +2557,13 @@
<permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to notify TV inputs by sending broadcasts.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.NOTIFY_TV_INPUTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
@hide -->
@@ -3129,6 +3182,15 @@
<permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
android:protectionLevel="signature" />
+ <!-- @SystemApi Must be required by services that extend
+ {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
+ bind to them.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link
android.service.notification.ConditionProviderService},
to ensure that only the system can bind to it.
@@ -3346,7 +3408,8 @@
android:documentLaunchMode="never"
android:relinquishTaskIdentity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3354,15 +3417,17 @@
</intent-filter>
</activity>
<activity android:name="com.android.internal.app.AccessibilityButtonChooserActivity"
+ android:exported="false"
android:theme="@style/Theme.DeviceDefault.Resolver"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:documentLaunchMode="never"
android:relinquishTaskIdentity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
<intent-filter>
- <action android:name="android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
+ <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -3421,7 +3486,8 @@
android:exported="true"
android:theme="@style/Theme.DeviceDefault.Light.Dialog"
android:label="@string/choose_account_label"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
@@ -3429,14 +3495,16 @@
android:exported="true"
android:theme="@style/Theme.DeviceDefault.Light.Dialog"
android:label="@string/choose_account_label"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
android:excludeFromRecents="true"
android:theme="@style/Theme.DeviceDefault.Light.Dialog"
android:label="@string/choose_account_label"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.accounts.CantAddAccountActivity"
@@ -3450,7 +3518,8 @@
android:excludeFromRecents="true"
android:exported="true"
android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
@@ -3508,6 +3577,11 @@
android:process=":ui">
</activity>
+ <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
+ android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
+
<receiver android:name="com.android.server.BootReceiver"
android:systemUserOnly="true">
<intent-filter android:priority="1000">
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 2cbc446..eb394b3 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -290,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/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 9a79c64..284841b 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -89,6 +89,10 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
+ <provider android:name="android.provider.cts.MockFontProvider"
+ android:authorities="android.provider.fonts.cts.font"
+ android:exported="false"
+ android:multiprocess="true" />
</application>
diff --git a/tests/tests/provider/assets/samplefont1.ttf b/tests/tests/provider/assets/samplefont1.ttf
new file mode 100644
index 0000000..020436a
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont1.ttf
Binary files differ
diff --git a/tests/tests/provider/assets/samplefont1.ttx b/tests/tests/provider/assets/samplefont1.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont1.ttx
@@ -0,0 +1,177 @@
+<?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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/provider/assets/samplefont2.ttf b/tests/tests/provider/assets/samplefont2.ttf
new file mode 100644
index 0000000..491540f
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont2.ttf
Binary files differ
diff --git a/tests/tests/provider/assets/samplefont2.ttx b/tests/tests/provider/assets/samplefont2.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont2.ttx
@@ -0,0 +1,177 @@
+<?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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/provider/src/android/provider/cts/FontsContractTest.java b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
new file mode 100644
index 0000000..d95f74a
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.provider.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.app.Instrumentation;
+import android.content.pm.Signature;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.graphics.fonts.FontRequest;
+import android.graphics.fonts.FontResult;
+import android.graphics.fonts.FontVariationAxis;
+import android.provider.FontsContract;
+import android.provider.FontsContract.FontFamilyResult;
+import android.provider.FontsContract.FontInfo;
+import android.provider.FontsContract.Columns;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FontsContractTest {
+ private static final String AUTHORITY = "android.provider.fonts.cts.font";
+ private static final String PACKAGE = "android.provider.cts";
+
+ private static long TIMEOUT_MILLIS = 1000;
+
+ // Signature to be used for authentication to access content provider.
+ // In this test case, the content provider and consumer live in the same package, self package's
+ // signature works.
+ private static List<List<byte[]>> SIGNATURE;
+ static {
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ try {
+ PackageManager manager = context.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(
+ context.getPackageName(), PackageManager.GET_SIGNATURES);
+ ArrayList<byte[]> out = new ArrayList<>();
+ for (Signature sig : info.signatures) {
+ out.add(sig.toByteArray());
+ }
+ SIGNATURE = new ArrayList<>();
+ SIGNATURE.add(out);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void querySingleFont() throws NameNotFoundException {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
+ FontFamilyResult result = FontsContract.fetchFonts(
+ ctx, null /* cancellation signal */, request);
+ assertNotNull(result);
+ assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+
+ FontInfo[] fonts = result.getFonts();
+ assertEquals(1, fonts.length);
+ FontInfo font = fonts[0];
+ assertNotNull(font.getUri());
+ assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
+ // TODO: add more test cases for FontInfo members once the MockFontProvider becomes
+ // configurable.
+ assertNotNull(FontsContract.buildTypeface(ctx, null /* cancellation signal */, fonts));
+ }
+
+ @Test
+ public void queryMultipleFont() throws NameNotFoundException {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "multipleFontFamily", SIGNATURE);
+ FontFamilyResult result = FontsContract.fetchFonts(
+ ctx, null /* cancellation signal */, request);
+ assertNotNull(result);
+ assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+
+ FontInfo[] fonts = result.getFonts();
+ assertEquals(4, fonts.length);
+ for (FontInfo font: fonts) {
+ assertNotNull(font.getUri());
+ assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
+ }
+ // TODO: add more test cases for FontInfo members once the MockFontProvider becomes
+ // configuarable.
+ assertNotNull(FontsContract.buildTypeface(ctx, null /* cancellation signal */, fonts));
+ }
+
+ @Test
+ public void restrictContextRejection() throws NameNotFoundException {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Context restrictedContext = ctx.createPackageContext(PACKAGE, Context.CONTEXT_RESTRICTED);
+
+ FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
+
+ // Rejected if restricted context is used.
+ FontFamilyResult result = FontsContract.fetchFonts(
+ restrictedContext, null /* cancellation signal */, request);
+ assertEquals(FontFamilyResult.STATUS_REJECTED, result.getStatusCode());
+
+ // Even if you have a result, buildTypeface should fail with restricted context.
+ result = FontsContract.fetchFonts(ctx, null /* cancellation signal */, request);
+ assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+ assertNull(FontsContract.buildTypeface(
+ restrictedContext, null /* cancellation signal */, result.getFonts()));
+ }
+
+ // TODO: Add more test case.
+}
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/provider/src/android/provider/cts/MockFontProvider.java b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
new file mode 100644
index 0000000..a348de2
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
@@ -0,0 +1,195 @@
+/*
+ * 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.provider.cts;
+
+import static android.provider.FontsContract.Columns;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.fonts.FontVariationAxis;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.util.SparseArray;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.File;
+import java.nio.file.Files;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.nio.file.StandardCopyOption;
+
+public class MockFontProvider extends ContentProvider {
+ final static String AUTHORITY = "android.provider.fonts.cts.font";
+
+ final static String[] FONT_FILES = {
+ "samplefont1.ttf", "samplefont2.ttf",
+ };
+ private static final int SAMPLE_FONT_FILE_0_ID = 0;
+ private static final int SAMPLE_FONT_FILE_1_ID = 1;
+
+ static class Font {
+ public Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
+ int resultCode) {
+ mId = id;
+ mFileId = fileId;
+ mTtcIndex = ttcIndex;
+ mVarSettings = varSettings;
+ mWeight = weight;
+ mItalic = italic;
+ mResultCode = resultCode;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getTtcIndex() {
+ return mTtcIndex;
+ }
+
+ public String getVarSettings() {
+ return mVarSettings;
+ }
+
+ public int getWeight() {
+ return mWeight;
+ }
+
+ public int getItalic() {
+ return mItalic;
+ }
+
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ public int getFileId() {
+ return mFileId;
+ }
+
+ private int mId;
+ private int mFileId;
+ private int mTtcIndex;
+ private String mVarSettings;
+ private int mWeight;
+ private int mItalic;
+ private int mResultCode;
+ };
+
+ private static Map<String, Font[]> QUERY_MAP;
+ static {
+ HashMap<String, Font[]> map = new HashMap<>();
+ int id = 0;
+
+ map.put("singleFontFamily", new Font[] {
+ new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+ });
+
+ map.put("multipleFontFamily", new Font[] {
+ new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+ new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+ new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK),
+ new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK),
+ });
+
+ QUERY_MAP = Collections.unmodifiableMap(map);
+ }
+
+ private static Cursor buildCursor(Font[] in) {
+ MatrixCursor cursor = new MatrixCursor(new String[] {
+ Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT,
+ Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID});
+ for (Font font : in) {
+ MatrixCursor.RowBuilder builder = cursor.newRow();
+ builder.add(Columns._ID, font.getId());
+ builder.add(Columns.FILE_ID, font.getFileId());
+ builder.add(Columns.TTC_INDEX, font.getTtcIndex());
+ builder.add(Columns.VARIATION_SETTINGS, font.getVarSettings());
+ builder.add(Columns.WEIGHT, font.getWeight());
+ builder.add(Columns.ITALIC, font.getItalic());
+ builder.add(Columns.RESULT_CODE, font.getResultCode());
+ }
+ return cursor;
+ }
+
+ public MockFontProvider() {
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) {
+ final int id = (int)ContentUris.parseId(uri);
+ final File targetFile = getCopiedFile(FONT_FILES[id]);
+ try {
+ return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public File getCopiedFile(String path) {
+ return new File(getContext().getFilesDir(), path);
+ }
+
+ @Override
+ public boolean onCreate() {
+ final AssetManager mgr = getContext().getAssets();
+ for (String path : FONT_FILES) {
+ try (InputStream is = mgr.open(path)) {
+ Files.copy(is, getCopiedFile(path).toPath(), StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ // TODO: do we have good time to remove above files from files directory?
+ return true;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "vnd.android.cursor.dir/vnd.android.provider.cts.font";
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return buildCursor(QUERY_MAP.get(selectionArgs[0]));
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException("insert is not supported.");
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("delete is not supported.");
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("update is not supported.");
+ }
+}
diff --git a/tests/tests/security/res/raw/cve_2015_3836.xmf b/tests/tests/security/res/raw/cve_2015_3836.xmf
new file mode 100644
index 0000000..b897c09
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3836.xmf
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4 b/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4
new file mode 100644
index 0000000..3d1b223
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4
Binary files differ
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..1ad199d 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -148,11 +148,21 @@
}
@SecurityTest
+ public void testStagefright_cve_2015_3836() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3836);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2015_3864() throws Exception {
doStagefrightTest(R.raw.cve_2015_3864);
}
@SecurityTest
+ public void testStagefright_cve_2015_3864_b23034759() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3864_b23034759);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2015_6598() throws Exception {
doStagefrightTest(R.raw.cve_2015_6598);
}
@@ -525,7 +535,11 @@
closeQuietly(fd);
}
} else {
- ex.setDataSource(url);
+ try {
+ ex.setDataSource(url);
+ } catch (Exception e) {
+ // indicative of problems with our tame CTS test web server
+ }
}
int numtracks = ex.getTrackCount();
String rname = url != null ? url: resources.getResourceEntryName(rid);
@@ -617,6 +631,7 @@
codec.release();
}
}
+ ex.unselectTrack(t);
}
ex.release();
String cve = rname.replace("_", "-").toUpperCase();
@@ -680,13 +695,17 @@
AssetFileDescriptor fd = resources.openRawResourceFd(rid);
try {
retriever.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- } catch (IllegalArgumentException e) {
+ } catch (RuntimeException e) {
// ignore
} finally {
closeQuietly(fd);
}
} else {
- retriever.setDataSource(url, new HashMap<String, String>());
+ try {
+ retriever.setDataSource(url, new HashMap<String, String>());
+ } catch (Exception e) {
+ // indicative of problems with our tame CTS test web server
+ }
}
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
retriever.getEmbeddedPicture();
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 543831c..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}.
*/
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 420bba1..a6404e0 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -183,10 +183,10 @@
mTelephonyManager.getNeighboringCellInfo();
mTelephonyManager.isNetworkRoaming();
mTelephonyManager.getDeviceId();
- mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
+ mTelephonyManager.getDeviceId(mTelephonyManager.getSlotIndex());
mTelephonyManager.getDeviceSoftwareVersion();
mTelephonyManager.getImei();
- mTelephonyManager.getImei(mTelephonyManager.getDefaultSim());
+ mTelephonyManager.getImei(mTelephonyManager.getSlotIndex());
mTelephonyManager.getPhoneCount();
mTelephonyManager.getDataEnabled();
mTelephonyManager.getNetworkSpecifier();
@@ -254,7 +254,7 @@
*/
@Test
public void testGetDeviceIdForSlot() {
- String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
+ String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getSlotIndex());
verifyDeviceId(deviceId);
// Also verify that no exception is thrown for any slot index (including invalid ones)
for (int i = -1; i <= mTelephonyManager.getPhoneCount(); i++) {
@@ -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/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/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/ActivityTransitionTest.java b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
index 54a567a..872820a 100644
--- a/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
@@ -95,6 +95,29 @@
TargetActivity.sLastCreated = null;
}
+ // When using ActivityOptions.makeBasic(), no transitions should run
+ @Test
+ public void testMakeBasic() {
+ assertFalse(mActivity.isActivityTransitionRunning());
+ mInstrumentation.runOnMainSync(() -> {
+ Intent intent = new Intent(mActivity, TargetActivity.class);
+ ActivityOptions activityOptions =
+ ActivityOptions.makeBasic();
+ mActivity.startActivity(intent, activityOptions.toBundle());
+ });
+
+ assertFalse(mActivity.isActivityTransitionRunning());
+
+ TargetActivity targetActivity = waitForTargetActivity();
+ assertFalse(targetActivity.isActivityTransitionRunning());
+ mInstrumentation.runOnMainSync(() -> {
+ targetActivity.finish();
+ });
+
+ assertFalse(targetActivity.isActivityTransitionRunning());
+ assertFalse(mActivity.isActivityTransitionRunning());
+ }
+
// Views that are outside the visible area only during the shared element start
// should not be stripped from the transition.
@Test
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/bitmapcomparers/BaseRenderScriptComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java
deleted file mode 100644
index 3f9a9f6..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package android.uirendering.cts.bitmapcomparers;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-
-/**
- * Base class for calculators that want to implement renderscript
- */
-public abstract class BaseRenderScriptComparer extends BitmapComparer {
- private Allocation mRowInputs;
- private Allocation mRowOutputs;
- private int mHeight;
-
- public abstract boolean verifySame(int[] ideal, int[] given, int offset, int stride, int width,
- int height);
-
- /**
- * The subclasses must implement this method, which will say that the rows follow their specific
- * algorithm
- */
- public abstract boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation);
-
- public boolean verifySameRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript) {
- if (mRowInputs == null) {
- mHeight = height;
- mRowInputs = createInputRowIndexAllocation(renderScript);
- mRowOutputs = createOutputRowAllocation(renderScript);
- }
- return verifySameRowsRS(resources, ideal, given, offset, stride, width, height,
- renderScript, mRowInputs, mRowOutputs);
- }
-
- public boolean supportsRenderScript() {
- return true;
- }
-
- /**
- * Sums the values in the output Allocation
- */
- public float sum1DFloatAllocation(Allocation rowOutputs) {
- //Get the values returned from the function
- float[] returnValue = new float[mHeight];
- rowOutputs.copyTo(returnValue);
- float sum = 0;
- //If any row had any different pixels, then it fails
- for (int i = 0; i < mHeight; i++) {
- sum += returnValue[i];
- }
- return sum;
- }
-
- /**
- * Creates an allocation where the values in it are the indices of each row
- */
- private Allocation createInputRowIndexAllocation(RenderScript renderScript) {
- //Create an array with the index of each row
- int[] inputIndices = new int[mHeight];
- for (int i = 0; i < mHeight; i++) {
- inputIndices[i] = i;
- }
- //Create the allocation from that given array
- Allocation inputAllocation = Allocation.createSized(renderScript, Element.I32(renderScript),
- inputIndices.length, Allocation.USAGE_SCRIPT);
- inputAllocation.copyFrom(inputIndices);
- return inputAllocation;
- }
-
- private Allocation createOutputRowAllocation(RenderScript renderScript) {
- return Allocation.createSized(renderScript, Element.F32(renderScript), mHeight,
- Allocation.USAGE_SCRIPT);
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
index 8d74aa5..c995e43 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
@@ -15,10 +15,6 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-
/**
* This abstract class can be used by the tester to implement their own comparison methods
*/
@@ -35,28 +31,9 @@
int height);
/**
- * Compare the two bitmaps using RenderScript, if the comparer
- * {@link supportsRenderScript() supports it}. If it does not, this method will throw an
- * UnsupportedOperationException
- */
- public boolean verifySameRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript) {
- throw new UnsupportedOperationException("Renderscript not supported for this calculator");
- }
-
- /**
* This calculates the position in an array that would represent a bitmap given the parameters.
*/
protected static int indexFromXAndY(int x, int y, int stride, int offset) {
return x + (y * stride) + offset;
}
-
- /**
- * Returns whether the verifySameRS() is implemented, and may be used on a RenderScript enabled
- * system
- */
- public boolean supportsRenderScript() {
- return false;
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
index 562b730..99d1f71 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
@@ -15,20 +15,13 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_ExactComparer;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.util.Log;
/**
* This class does an exact comparison of the pixels in a bitmap.
*/
-public class ExactComparer extends BaseRenderScriptComparer {
+public class ExactComparer extends BitmapComparer {
private static final String TAG = "ExactComparer";
- private ScriptC_ExactComparer mScript;
/**
* This method does an exact 1 to 1 comparison of the two bitmaps
@@ -54,27 +47,4 @@
return (count == 0);
}
-
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_ExactComparer(renderScript);
- }
- mScript.set_WIDTH(width);
- mScript.set_OFFSET(offset);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_exactCompare(inputAllocation, outputAllocation);
-
- float val = sum1DFloatAllocation(outputAllocation);
- Log.d(TAG, "Number of different pixels RS : " + val);
-
- return val == 0;
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
deleted file mode 100644
index 6425c17..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int OFFSET;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a simple comparison of all the values in the given and ideal allocations.
-// If any of the pixels are off, then the test will fail.
-void exactCompare(const int32_t *v_in, float *v_out){
- int y = v_in[0];
- v_out[0] = 0;
-
- for(int i = 0 ; i < WIDTH ; i ++){
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i + OFFSET, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i + OFFSET, y);
- uchar4 diff = idealPixel - givenPixel;
- int totalDiff = diff.x + diff.y + diff.z;
- if(totalDiff != 0){
- v_out[0] ++;
- }
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
index 4a25695..e65ff2d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
@@ -15,12 +15,7 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.ScriptC_MSSIMComparer;
-
-import android.content.res.Resources;
import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.util.Log;
/**
@@ -29,7 +24,7 @@
*
* https://ece.uwaterloo.ca/~z70wang/publications/ssim.pdf
*/
-public class MSSIMComparer extends BaseRenderScriptComparer {
+public class MSSIMComparer extends BitmapComparer {
// These values were taken from the publication
public static final String TAG_NAME = "MSSIM";
public static final double CONSTANT_L = 254;
@@ -40,7 +35,6 @@
public static final int WINDOW_SIZE = 10;
private double mThreshold;
- private ScriptC_MSSIMComparer mScript;
public MSSIMComparer(double threshold) {
mThreshold = threshold;
@@ -82,31 +76,6 @@
return (SSIMTotal >= mThreshold);
}
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_MSSIMComparer(renderScript);
- }
- mScript.set_WIDTH(width);
- mScript.set_HEIGHT(height);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_calcSSIM(inputAllocation, outputAllocation);
-
- float MSSIM = sum1DFloatAllocation(outputAllocation);
- MSSIM /= height;
-
- Log.d(TAG_NAME, "MSSIM RS : " + MSSIM);
-
- return (MSSIM >= mThreshold);
- }
-
private boolean isWindowWhite(int[] colors, int start, int stride) {
for (int y = 0 ; y < WINDOW_SIZE ; y++) {
for (int x = 0 ; x < WINDOW_SIZE ; x++) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
deleted file mode 100644
index b0e86b8..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int HEIGHT;
-
-rs_allocation ideal;
-rs_allocation given;
-
-static float getPixelWeight(uchar4 pixel) {
- const float MAX_VALUE_COLOR = 255;
- const float RED_WEIGHT = 0.21f / MAX_VALUE_COLOR;
- const float GREEN_WEIGHT = 0.72f / MAX_VALUE_COLOR;
- const float BLUE_WEIGHT = 0.07f / MAX_VALUE_COLOR;
- return (pixel.r * RED_WEIGHT) + (pixel.g * GREEN_WEIGHT) + (pixel.b * BLUE_WEIGHT);
-}
-
-// Calculates SSIM of a row of pixels
-void calcSSIM(const int32_t *v_in, float *v_out) {
- // TODO Test values for these constants
- const float C1 = 0.0000064516;
- const float C2 = 0.0000580644;
-
- int y = v_in[0];
- v_out[0] = 0;
-
- float meanIdeal = 0;
- float meanGiven = 0;
-
- for (int i = 0 ; i < WIDTH ; i++) {
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
- meanIdeal += getPixelWeight(idealPixel);
- meanGiven += getPixelWeight(givenPixel);
- }
-
- meanIdeal /= WIDTH;
- meanGiven /= WIDTH;
-
- float varIdeal = 0;
- float varGiven = 0;
- float varBoth = 0;
-
- for (int i = 0 ; i < WIDTH ; i++) {
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
- float idealWeight = getPixelWeight(idealPixel);
- float givenWeight = getPixelWeight(givenPixel);
- idealWeight -= meanIdeal;
- givenWeight -= meanGiven;
- varIdeal += idealWeight * idealWeight;
- varGiven += givenWeight * givenWeight;
- varBoth += idealWeight * givenWeight;
- }
-
- varIdeal /= WIDTH - 1;
- varGiven /= WIDTH - 1;
- varBoth /= WIDTH - 1;
-
- float SSIM = ((2 * meanIdeal * meanGiven) + C1) * ((2 * varBoth) + C2);
- float denom = ((meanIdeal * meanIdeal) + (meanGiven * meanGiven) + C1)
- * (varIdeal + varGiven + C2);
- SSIM /= denom;
-
- v_out[0] = SSIM;
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
index 5cc896b..2b6ba0c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
@@ -15,21 +15,14 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_MeanSquaredComparer;
-
-import android.content.res.Resources;
import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.util.Log;
/**
* Finds the MSE using two images.
*/
-public class MeanSquaredComparer extends BaseRenderScriptComparer {
+public class MeanSquaredComparer extends BitmapComparer {
private static final String TAG = "MeanSquared";
- private ScriptC_MeanSquaredComparer mScript;
private float mErrorPerPixel;
/**
@@ -48,30 +41,6 @@
return (totalError < (mErrorPerPixel));
}
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_MeanSquaredComparer(renderScript);
- }
- mScript.set_WIDTH(width);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_calcMSE(inputAllocation, outputAllocation);
-
- float error = sum1DFloatAllocation(outputAllocation);
- error /= (height * width);
-
- Log.d(TAG, "Error RS : " + error);
-
- return (error < mErrorPerPixel);
- }
-
/**
* Gets the Mean Squared Error between two data sets.
*/
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
deleted file mode 100644
index 3b37609..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int REGION_SIZE;
-int WIDTH;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a threshold comparison of the values
-void calcMSE(const int32_t *v_in, float *v_out){
- int y = v_in[0];
- v_out[0] = 0.0f;
- for (int x = 0 ; x < WIDTH ; x++) {
- float4 idealFloats = rsUnpackColor8888(rsGetElementAt_uchar4(ideal, x, y));
- float4 givenFloats = rsUnpackColor8888(rsGetElementAt_uchar4(given, x, y));
- float difference = (idealFloats.r - givenFloats.r) + (idealFloats.g - givenFloats.g) +
- (idealFloats.b - givenFloats.b);
- v_out[0] += (difference * difference);
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
index 6a78f11..b7a608a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
@@ -15,22 +15,14 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_ThresholdDifferenceComparer;
-
-import android.content.res.Resources;
import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-import android.uirendering.cts.bitmapcomparers.BaseRenderScriptComparer;
import android.util.Log;
/**
* Compares two images to see if each pixel is the same, within a certain threshold value
*/
-public class ThresholdDifferenceComparer extends BaseRenderScriptComparer {
+public class ThresholdDifferenceComparer extends BitmapComparer {
private static final String TAG = "ThresholdDifference";
- private ScriptC_ThresholdDifferenceComparer mScript;
private int mThreshold;
/**
@@ -63,27 +55,4 @@
Log.d(TAG, "Number of different pixels : " + differentPixels);
return (differentPixels == 0);
}
-
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_ThresholdDifferenceComparer(renderScript);
- }
-
- mScript.set_THRESHOLD(mThreshold);
- mScript.set_WIDTH(width);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_thresholdCompare(inputAllocation, outputAllocation);
-
- float differentPixels = sum1DFloatAllocation(outputAllocation);
- Log.d(TAG, "Number of different pixels RS : " + differentPixels);
- return (differentPixels == 0);
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
deleted file mode 100644
index 8a40ad6..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int THRESHOLD;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a threshold comparison of the values
-void thresholdCompare(const int32_t *v_in, float *v_out){
- int y = v_in[0];
- v_out[0] = 0;
-
- for(int i = 0 ; i < WIDTH ; i ++){
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
- float l1 = (idealPixel.x * 0.21f) + (idealPixel.y * 0.72f) + (idealPixel.z * 0.07f);
- float l2 = (givenPixel.x * 0.21f) + (givenPixel.y * 0.72f) + (givenPixel.z * 0.07f);
- float diff = l1 - l2;
- if (fabs(diff) >= THRESHOLD) {
- v_out[0]++;
- }
- }
-}
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..f0afd53 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
@@ -24,9 +24,11 @@
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;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.ColorCountVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -41,7 +43,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@MediumTest
+import java.util.Arrays;
+
+@LargeTest
@RunWith(AndroidJUnit4.class)
public class BitmapTests extends ActivityTestBase {
class BitmapView extends View {
@@ -146,21 +150,17 @@
*/
@Test
public void testChangeDuringUiAnimation() {
- class PureBlueOrRedVerifier extends BitmapVerifier {
+ class BlueOrRedVerifier extends BitmapVerifier {
@Override
public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
- int blueCount = 0;
- int redCount = 0;
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; y++) {
- if (bitmap[indexFromXAndY(x, y, stride, offset)] == Color.BLUE) {
- blueCount++;
- } else if (bitmap[indexFromXAndY(x, y, stride, offset)] == Color.RED) {
- redCount++;
- }
- }
- }
- return blueCount == width * height || redCount == width * height;
+ MSSIMComparer comparer = new MSSIMComparer(0.99);
+ int[] red = new int[offset + height * stride];
+ Arrays.fill(red, Color.RED);
+ int[] blue = new int[offset + height * stride];
+ Arrays.fill(blue, Color.BLUE);
+ boolean isRed = comparer.verifySame(red, bitmap, offset, stride, width, height);
+ boolean isBlue = comparer.verifySame(blue, bitmap, offset, stride, width, height);
+ return isRed || isBlue;
}
}
@@ -210,6 +210,6 @@
createTest()
.addLayout(R.layout.frame_layout, initializer, true)
- .runWithAnimationVerifier(new PureBlueOrRedVerifier());
+ .runWithAnimationVerifier(new BlueOrRedVerifier());
}
}
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/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
index 5a3331c..d5f9324 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
@@ -20,17 +20,13 @@
import android.content.Context;
import android.graphics.Bitmap;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
public class BitmapAsserter {
- public static final boolean USE_RS = false;
private DifferenceVisualizer mDifferenceVisualizer;
- private RenderScript mRenderScript;
private Context mContext;
private String mClassName;
@@ -50,9 +46,6 @@
public void setUp(Context context) {
mDifferenceVisualizer = new PassFailVisualizer();
mContext = context;
- if (USE_RS) {
- mRenderScript = RenderScript.create(context.getApplicationContext());
- }
}
/**
@@ -69,20 +62,11 @@
fail("Can't compare bitmaps of different sizes");
}
- if (USE_RS && comparer.supportsRenderScript()) {
- Allocation idealAllocation = Allocation.createFromBitmap(mRenderScript, bitmap1,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- Allocation givenAllocation = Allocation.createFromBitmap(mRenderScript, bitmap2,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- success = comparer.verifySameRS(mContext.getResources(), idealAllocation,
- givenAllocation, 0, width, width, height, mRenderScript);
- } else {
- int[] pixels1 = new int[width * height];
- int[] pixels2 = new int[width * height];
- bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
- bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
- success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
- }
+ int[] pixels1 = new int[width * height];
+ int[] pixels2 = new int[width * height];
+ bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
+ bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
+ success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
if (!success) {
BitmapDumper.dumpBitmaps(bitmap1, bitmap2, testName, mClassName, mDifferenceVisualizer);
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/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
index c54f183..72c89df 100644
--- a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
+++ b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
@@ -71,22 +71,7 @@
return;
}
- final View content = mActivity.findViewById(android.R.id.content);
- assertNotNull(content);
- final ViewParent viewParent = content.getParent();
- assertNotNull(viewParent);
- assertTrue(viewParent instanceof ViewGroup);
- ViewGroup parent = (ViewGroup) viewParent;
- View actionBarView = null;
- for (int i = 0; i < parent.getChildCount(); i++) {
- View child = parent.getChildAt(i);
- if ("android:action_bar".equals(child.getTransitionName())) {
- actionBarView = child;
- break;
- }
- }
- assertNotNull(actionBarView);
- final View actionBar = actionBarView;
+ final View actionBar = getActionBarView();
// Should jump to the action bar after meta+tab
mActivityRule.runOnUiThread(() -> {
assertFalse(v1.hasFocus());
@@ -118,6 +103,47 @@
}
}
+ @Test
+ public void testNoFocusablesInContent() throws Throwable {
+ ViewGroup top = mActivity.findViewById(R.id.linearlayout);
+ top.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ mActivityRule.runOnUiThread(top::clearFocus);
+ mInstrumentation.waitForIdleSync();
+ top.clearFocus();
+ final View content = mActivity.findViewById(android.R.id.content);
+ assertTrue(content.findFocus() == null);
+ sendMetaHotkey(KeyEvent.KEYCODE_TAB);
+ mInstrumentation.waitForIdleSync();
+
+ ActionBar action = mActivity.getActionBar();
+ if (action == null || !action.isShowing()) {
+ // No action bar, so we only needed to make sure that the shortcut didn't cause
+ // the framework to crash.
+ return;
+ }
+
+ assertTrue(getActionBarView().hasFocus());
+ }
+
+ private View getActionBarView() {
+ final View content = mActivity.findViewById(android.R.id.content);
+ assertNotNull(content);
+ final ViewParent viewParent = content.getParent();
+ assertNotNull(viewParent);
+ assertTrue(viewParent instanceof ViewGroup);
+ ViewGroup parent = (ViewGroup) viewParent;
+ View actionBarView = null;
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ View child = parent.getChildAt(i);
+ if ("android:action_bar".equals(child.getTransitionName())) {
+ actionBarView = child;
+ break;
+ }
+ }
+ assertNotNull(actionBarView);
+ return actionBarView;
+ }
+
private void sendMetaHotkey(int keyCode) throws Throwable {
sendMetaKey(KeyEvent.ACTION_DOWN);
long time = SystemClock.uptimeMillis();
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/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 472e371..8caf161 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -1005,6 +1005,18 @@
}
}
+ public void testEnableSafeBrowsing() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ assertFalse(mSettings.getSafeBrowsingEnabled());
+ mSettings.setSafeBrowsingEnabled(true);
+ assertTrue(mSettings.getSafeBrowsingEnabled());
+ mSettings.setSafeBrowsingEnabled(false);
+ assertFalse(mSettings.getSafeBrowsingEnabled());
+ }
+
+
/**
* Starts the internal web server. The server will be shut down automatically
* during tearDown().
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 07ba11e..d77af03 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -582,14 +582,14 @@
}
final MockWebViewClient webViewClient = new MockWebViewClient();
mOnUiThread.setWebViewClient(webViewClient);
- mOnUiThread.loadUrl("chrome://crash");
+ mOnUiThread.loadUrl("chrome://kill");
new PollingCheck(TEST_TIMEOUT * 5) {
@Override
protected boolean check() {
return webViewClient.hasRenderProcessGoneCalled();
}
}.run();
- assertTrue(webViewClient.didRenderProcessCrash());
+ assertFalse(webViewClient.didRenderProcessCrash());
}
private void requireLoadedPage() throws Throwable {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 2ef274a..4ff8eef 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -26,7 +26,6 @@
import android.graphics.Color;
import android.graphics.Picture;
import android.graphics.Rect;
-import android.graphics.pdf.PdfRenderer;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -2551,8 +2550,7 @@
// Called on UI thread
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- PageRange[] pageRanges = new PageRange[] {PageRange.ALL_PAGES};
- savePrintedPage(adapter, descriptor, pageRanges, result);
+ savePrintedPage(adapter, descriptor, result);
}
});
try {
@@ -2570,57 +2568,6 @@
}
}
- // Verify Print feature can create a PDF file with correct number of pages.
- public void testPrintingPagesCount() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- String content = "<html><head></head><body>";
- for (int i = 0; i < 500; ++i) {
- content += "<br />abcdefghijk<br />";
- }
- content += "</body></html>";
- mOnUiThread.loadDataAndWaitForCompletion(content, "text/html", null);
- final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
- printDocumentStart(adapter);
- PrintAttributes attributes = new PrintAttributes.Builder()
- .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
- .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
- .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
- .build();
- final WebViewCtsActivity activity = getActivity();
- final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
- final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
- ParcelFileDescriptor.parseMode("w"));
- final FutureTask<Boolean> result =
- new FutureTask<Boolean>(new Callable<Boolean>() {
- public Boolean call() {
- return true;
- }
- });
- printDocumentLayout(adapter, null, attributes,
- new LayoutResultCallback() {
- // Called on UI thread
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- PageRange[] pageRanges = new PageRange[] {
- new PageRange(1, 1), new PageRange(4, 7)
- };
- savePrintedPage(adapter, descriptor, pageRanges, result);
- }
- });
- try {
- result.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
- assertTrue(file.length() > 0);
- PdfRenderer renderer = new PdfRenderer(
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
- assertEquals(5, renderer.getPageCount());
- } finally {
- descriptor.close();
- file.delete();
- }
- }
-
public void testVisualStateCallbackCalled() throws Exception {
// Check that the visual state callback is called correctly.
if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -2692,9 +2639,8 @@
}
private void savePrintedPage(final PrintDocumentAdapter adapter,
- final ParcelFileDescriptor descriptor, final PageRange[] pageRanges,
- final FutureTask<Boolean> result) {
- adapter.onWrite(pageRanges, descriptor,
+ final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
+ adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
new CancellationSignal(),
new WriteResultCallback() {
@Override
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/SearchView_CursorTest.java b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
index b1523c5..2cc8993 100644
--- a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
@@ -37,6 +37,9 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AutoCompleteTextView;
import android.widget.CursorAdapter;
import android.widget.SearchView;
import android.widget.SimpleCursorAdapter;
@@ -64,6 +67,7 @@
private CursorAdapter mSuggestionsAdapter;
+ // This should be protected to spy an object of this class.
protected class MyQueryTextListener implements SearchView.OnQueryTextListener {
@Override
public boolean onQueryTextSubmit(String s) {
@@ -75,7 +79,9 @@
if (mSuggestionsAdapter == null) {
return false;
}
-
+ if (!enoughToFilter()) {
+ return false;
+ }
final MatrixCursor c = new MatrixCursor(
new String[] { BaseColumns._ID, TEXT_COLUMN_NAME} );
for (int i = 0; i < mTextContent.length; i++) {
@@ -86,8 +92,32 @@
mSuggestionsAdapter.swapCursor(c);
return false;
}
+
+ private boolean enoughToFilter() {
+ final AutoCompleteTextView searchSrcText = findAutoCompleteTextView(mSearchView);
+ return searchSrcText != null && searchSrcText.enoughToFilter();
+ }
+
+ private AutoCompleteTextView findAutoCompleteTextView(final ViewGroup viewGroup) {
+ final int count = viewGroup.getChildCount();
+ for (int index = 0; index < count; index++) {
+ final View view = viewGroup.getChildAt(index);
+ if (view instanceof AutoCompleteTextView) {
+ return (AutoCompleteTextView) view;
+ }
+ if (view instanceof ViewGroup) {
+ final AutoCompleteTextView findView =
+ findAutoCompleteTextView((ViewGroup) view);
+ if (findView != null) {
+ return findView;
+ }
+ }
+ }
+ return null;
+ }
}
+ // This should be protected to spy an object of this class.
protected class MySuggestionListener implements SearchView.OnSuggestionListener {
@Override
public boolean onSuggestionSelect(int position) {
@@ -103,7 +133,7 @@
mSearchView.setQuery(cursor.getString(1), false);
}
}
- return false;
+ return true;
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 0b500f3..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)
@@ -4532,7 +4652,7 @@
| InputType.TYPE_NUMBER_FLAG_DECIMAL
| InputType.TYPE_NUMBER_FLAG_SIGNED, mTextView.getInputType());
assertSame(mTextView.getKeyListener(),
- DigitsKeyListener.getInstance(mTextView.getTextLocale(), true, true));
+ DigitsKeyListener.getInstance(null, true, true));
mTextView.setInputType(InputType.TYPE_CLASS_PHONE);
assertEquals(InputType.TYPE_CLASS_PHONE, mTextView.getInputType());
@@ -4748,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),
@@ -5392,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());
@@ -6387,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());
@@ -6396,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.
@@ -6567,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
@@ -6713,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(
@@ -7270,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);
@@ -7411,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" />