Merge "KeyChain: Adopt to null return value"
diff --git a/apps/CtsVerifier/res/layout/biometric_test_main.xml b/apps/CtsVerifier/res/layout/biometric_test_main.xml
index 75a42f9..476e355 100644
--- a/apps/CtsVerifier/res/layout/biometric_test_main.xml
+++ b/apps/CtsVerifier/res/layout/biometric_test_main.xml
@@ -20,28 +20,51 @@
android:padding="10dip"
>
- <Button android:id="@+id/biometric_start_test1_button"
+ <Button android:id="@+id/biometric_enroll_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/biometric_start_test_not_secured"
+ android:layout_centerHorizontal="true"
+ android:text="@string/biometric_enroll"
+ android:visibility="invisible"
+ />
+
+ <Button android:id="@+id/biometric_start_test_not_secured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/biometric_start_test1"
/>
- <Button android:id="@+id/biometric_enroll_button"
+ <Button android:id="@+id/biometric_start_test_none_enrolled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_above="@+id/biometric_start_test2_button"
android:layout_centerHorizontal="true"
- android:text="@string/biometric_enroll"
+ android:layout_below="@+id/biometric_start_test_not_secured"
+ android:text="@string/biometric_start_test2"
+ android:visibility="invisible"
/>
- <Button android:id="@+id/biometric_start_test2_button"
+ <Button android:id="@+id/biometric_start_test_credential_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="@string/biometric_start_test2"
+ android:layout_below="@+id/biometric_start_test_none_enrolled"
+ android:layout_centerHorizontal="true"
+ android:text="@string/biometric_start_test3"
+ android:visibility="invisible"
/>
+ <Button android:id="@+id/biometric_start_test_authenticate_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/biometric_start_test_fallback_button"
+ android:layout_centerHorizontal="true"
+ android:text="@string/biometric_start_test4"
+ android:visibility="invisible"
+ />
+
+
+
<include android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index b20e8a6..a6bb079 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -157,6 +157,8 @@
<string name="biometric_enroll">Enroll</string>
<string name="biometric_start_test1">Start Test 1</string>
<string name="biometric_start_test2">Start Test 2</string>
+ <string name="biometric_start_test3">Start Test 3</string>
+ <string name="biometric_start_test4">Start Test 4</string>
<!-- Strings for lock bound keys test -->
<string name="sec_lock_bound_key_test">Lock Bound Keys Test</string>
@@ -1448,10 +1450,8 @@
Test failed.\n\nUnexpected error. Check logcat.</string>
<string name="wifi_status_initiating_scan">Initiating scan.</string>
- <string name="wifi_status_scan_failure">Unable to initiate scan.</string>
- <string name="wifi_status_open_network_not_found">Unable to find any open network in scan results.</string>
+ <string name="wifi_status_scan_failure">Unable to initiate scan or find any open network in scan results.</string>
<string name="wifi_status_connected_to_other_network">Connected to some other network on the device. Please ensure that there is no saved networks on the device.</string>
-
<string name="wifi_status_initiating_network_request">Initiating network request.</string>
<string name="wifi_status_network_wait_for_available">Waiting for network connection. Please click the network in the dialog that pops up for approving the request.</string>
<string name="wifi_status_network_available">"Connected to network."</string>
@@ -1487,9 +1487,9 @@
<string name="wifi_test_network_suggestion">Network Suggestion tests</string>
<string name="wifi_test_network_suggestion_ssid">Network suggestion with SSID.</string>
<string name="wifi_test_network_suggestion_ssid_info">Tests whether the API can be used to suggest a network with SSID to the device and the device connects to it.</string>
- <string name="wifi_test_network_suggestion_ssid_bssid">Network Request with a specific SSID and BSSID.</string>
+ <string name="wifi_test_network_suggestion_ssid_bssid">Network suggestion with SSID and BSSID.</string>
<string name="wifi_test_network_suggestion_ssid_bssid_info">Tests whether the API can be used to suggest a network with SSID and specific BSSID to the device and the device connects to it.</string>
- <string name="wifi_test_network_suggestion_ssid_post_connect">Network Request with a specific SSID and BSSID.</string>
+ <string name="wifi_test_network_suggestion_ssid_post_connect">Network suggestion with SSID and post connection broadcast.</string>
<string name="wifi_test_network_suggestion_ssid_post_connect_info">Tests whether the API can be used to suggest a network with SSID to the device and the device connects to it and sends the post connect broadcast back to the app.</string>
<!-- Strings for P2pTestActivity -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
index 31b43b4..ac9c465 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
@@ -17,6 +17,7 @@
package com.android.cts.verifier.biometrics;
import android.Manifest;
+import android.app.KeyguardManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -49,17 +50,29 @@
private static final String BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
private static final int BIOMETRIC_PERMISSION_REQUEST_CODE = 0;
- private static final int TEST_NONE_ENROLLED = 1;
- private static final int TEST_ENROLLED = 2;
+ // Test that BiometricPrompt setAllowDeviceCredentials returns ERROR_NO_DEVICE_CREDENTIAL when
+ // pin, pattern, password is not set.
+ private static final int TEST_NOT_SECURED = 1;
+ // Test that BiometricPrompt returns BIOMETRIC_ERROR_NO_BIOMETRICS when BiometricManager
+ // states BIOMETRIC_ERROR_NONE_ENROLLED.
+ private static final int TEST_NONE_ENROLLED = 2;
+ // Test that BiometricPrompt setAllowDeviceCredentials can authenticate when no biometrics are
+ // enrolled.
+ private static final int TEST_DEVICE_CREDENTIAL = 3;
+ // Test that authentication can succeed when biometrics are enrolled.
+ private static final int TEST_AUTHENTICATE = 4;
private BiometricManager mBiometricManager;
+ private KeyguardManager mKeyguardManager;
private Handler mHandler = new Handler(Looper.getMainLooper());
private CancellationSignal mCancellationSignal;
- private int mExpectedError;
private int mCurrentTest;
+
private Button mButtonEnroll;
- private Button mButtonTest1;
- private Button mButtonTest2;
+ private Button mButtonTestNotSecured;
+ private Button mButtonTestNoneEnrolled;
+ private Button mButtonTestCredential;
+ private Button mButtonTestAuthenticate;
private Executor mExecutor = (runnable) -> {
mHandler.post(runnable);
@@ -69,27 +82,45 @@
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
- if (mCurrentTest == TEST_NONE_ENROLLED) {
- showToastAndLog("This should be impossible, please capture a bug report");
- } else if (mCurrentTest == TEST_ENROLLED) {
- showToastAndLog("Authenticated. You passed the test.");
+ if (mCurrentTest == TEST_NOT_SECURED) {
+ showToastAndLog("This should be impossible, please capture a bug report "
+ + mCurrentTest);
+ } else if (mCurrentTest == TEST_NONE_ENROLLED) {
+ showToastAndLog("This should be impossible, please capture a bug report"
+ + mCurrentTest);
+ } else if (mCurrentTest == TEST_DEVICE_CREDENTIAL) {
+ showToastAndLog("Please enroll a biometric and start the next test");
+ mButtonTestCredential.setEnabled(false);
+ mButtonEnroll.setVisibility(View.VISIBLE);
+ mButtonTestAuthenticate.setVisibility(View.VISIBLE);
+ } else if (mCurrentTest == TEST_AUTHENTICATE) {
+ showToastAndLog("You have passed the test!");
+ mButtonTestAuthenticate.setEnabled(false);
getPassButton().setEnabled(true);
}
}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
- if (mCurrentTest == TEST_NONE_ENROLLED) {
- if (errorCode == mExpectedError) {
- mButtonTest1.setVisibility(View.INVISIBLE);
- mButtonTest2.setVisibility(View.VISIBLE);
- mButtonEnroll.setVisibility(View.VISIBLE);
- showToastAndLog("Please enroll a biometric and start the next test");
+ if (mCurrentTest == TEST_NOT_SECURED) {
+ if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL) {
+ showToastAndLog("Please start the next test");
+ mButtonTestNotSecured.setEnabled(false);
+ mButtonTestNoneEnrolled.setVisibility(View.VISIBLE);
} else {
- showToastAndLog("Expected: " + mExpectedError +
- " Actual: " + errorCode + " " + errString);
+ showToastAndLog("Error: " + errorCode + " " + errString);
}
- } else if (mCurrentTest == TEST_ENROLLED) {
+ } else if (mCurrentTest == TEST_NONE_ENROLLED) {
+ if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS) {
+ mButtonTestNoneEnrolled.setEnabled(false);
+ mButtonTestCredential.setVisibility(View.VISIBLE);
+ showToastAndLog("Please start the next test");
+ } else {
+ showToastAndLog("Error: " + errorCode + " " + errString);
+ }
+ } else if (mCurrentTest == TEST_DEVICE_CREDENTIAL) {
+ showToastAndLog(errString.toString() + " Please try again");
+ } else if (mCurrentTest == TEST_AUTHENTICATE) {
showToastAndLog(errString.toString() + " Please try again");
}
}
@@ -108,11 +139,12 @@
getPassButton().setEnabled(false);
mBiometricManager = getApplicationContext().getSystemService(BiometricManager.class);
+ mKeyguardManager = getApplicationContext().getSystemService(KeyguardManager.class);
mButtonEnroll = findViewById(R.id.biometric_enroll_button);
- mButtonEnroll.setVisibility(View.INVISIBLE);
- mButtonTest1 = findViewById(R.id.biometric_start_test1_button);
- mButtonTest2 = findViewById(R.id.biometric_start_test2_button);
- mButtonTest2.setVisibility(View.INVISIBLE);
+ mButtonTestNoneEnrolled = findViewById(R.id.biometric_start_test_none_enrolled);
+ mButtonTestNotSecured = findViewById(R.id.biometric_start_test_not_secured);
+ mButtonTestAuthenticate = findViewById(R.id.biometric_start_test_authenticate_button);
+ mButtonTestCredential = findViewById(R.id.biometric_start_test_credential_button);
PackageManager pm = getApplicationContext().getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
@@ -120,21 +152,28 @@
|| pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
requestPermissions(new String[]{Manifest.permission.USE_BIOMETRIC},
BIOMETRIC_PERMISSION_REQUEST_CODE);
- mButtonTest1.setEnabled(false);
- mButtonTest1.setOnClickListener((view) -> {
+
+ mButtonTestNotSecured.setEnabled(false);
+ mButtonTestNotSecured.setOnClickListener((view) -> {
+ startTest(TEST_NOT_SECURED);
+ });
+ mButtonTestNoneEnrolled.setOnClickListener((view) -> {
startTest(TEST_NONE_ENROLLED);
});
- mButtonTest2.setOnClickListener((view) -> {
- startTest(TEST_ENROLLED);
+ mButtonTestAuthenticate.setOnClickListener((view) -> {
+ startTest(TEST_AUTHENTICATE);
});
mButtonEnroll.setOnClickListener((view) -> {
final Intent intent = new Intent();
intent.setAction(BIOMETRIC_ENROLL);
startActivity(intent);
});
+ mButtonTestCredential.setOnClickListener((view) -> {
+ startTest(TEST_DEVICE_CREDENTIAL);
+ });
} else {
// NO biometrics available
- mButtonTest1.setEnabled(false);
+ mButtonTestNoneEnrolled.setEnabled(false);
getPassButton().setEnabled(true);
}
}
@@ -143,7 +182,7 @@
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] state) {
if (requestCode == BIOMETRIC_PERMISSION_REQUEST_CODE &&
state[0] == PackageManager.PERMISSION_GRANTED) {
- mButtonTest1.setEnabled(true);
+ mButtonTestNotSecured.setEnabled(true);
}
}
@@ -151,17 +190,29 @@
mCurrentTest = testType;
int result = mBiometricManager.canAuthenticate();
- if (testType == TEST_NONE_ENROLLED) {
+ if (testType == TEST_NOT_SECURED) {
+ if (mKeyguardManager.isDeviceSecure()) {
+ showToastAndLog("Please remove your pin/pattern/password and try again");
+ } else {
+ showBiometricPrompt(true /* allowCredential */);
+ }
+ } else if (testType == TEST_NONE_ENROLLED) {
if (result == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
- mExpectedError = BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS;
- showBiometricPrompt();
+ showBiometricPrompt(false /* allowCredential */);
} else {
showToastAndLog("Error: " + result + " Please remove all biometrics and try again");
}
- } else if (testType == TEST_ENROLLED) {
+ } else if (testType == TEST_DEVICE_CREDENTIAL) {
+ if (!mKeyguardManager.isDeviceSecure()) {
+ showToastAndLog("Please set up a pin, pattern, or password and try again");
+ } else if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
+ showToastAndLog("Error: " + result + " Please remove all biometrics and try again");
+ } else {
+ showBiometricPrompt(true /* allowCredential */);
+ }
+ } else if (testType == TEST_AUTHENTICATE) {
if (result == BiometricManager.BIOMETRIC_SUCCESS) {
- mExpectedError = 0;
- showBiometricPrompt();
+ showBiometricPrompt(false /* allowCredential */);
} else {
showToastAndLog("Error: " + result +
" Please ensure at least one biometric is enrolled and try again");
@@ -171,10 +222,14 @@
}
}
- private void showBiometricPrompt() {
+ private void showBiometricPrompt(boolean allowCredential) {
BiometricPrompt.Builder builder = new BiometricPrompt.Builder(getApplicationContext())
- .setTitle("Please authenticate")
- .setNegativeButton("Cancel", mExecutor, mBiometricPromptButtonListener);
+ .setTitle("Please authenticate");
+ if (allowCredential) {
+ builder.setAllowDeviceCredential(true);
+ } else {
+ builder.setNegativeButton("Cancel", mExecutor, mBiometricPromptButtonListener);
+ }
BiometricPrompt bp = builder.build();
mCancellationSignal = new CancellationSignal();
bp.authenticate(mCancellationSignal, mExecutor, mAuthenticationCallback);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java
index 920119f..2ab8bdb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/BaseTestCase.java
@@ -16,11 +16,8 @@
package com.android.cts.verifier.wifi;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
-import android.net.wifi.SupplicantState;
-import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.HandlerThread;
@@ -40,8 +37,8 @@
private Thread mThread;
private HandlerThread mHandlerThread;
protected Handler mHandler;
-
protected WifiManager mWifiManager;
+ protected TestUtils mTestUtils;
public BaseTestCase(Context context) {
mContext = context;
@@ -53,9 +50,10 @@
*/
protected void setUp() {
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ mTestUtils = new TestUtils(mContext, mListener);
// Ensure we're not connected to any wifi network before we start the tests.
- if (isConnected(null, null)) {
+ if (mTestUtils.isConnected(null, null)) {
mListener.onTestFailed(mContext.getString(
R.string.wifi_status_connected_to_other_network));
throw new IllegalStateException("Should not be connected to any network");
@@ -71,27 +69,6 @@
}
/**
- * Checks whether the device is connected.
- *
- * @param ssid If ssid is specified, then check where the device is connected to a network
- * with the specified SSID.
- * @param bssid If bssid is specified, then check where the device is connected to a network
- * with the specified BSSID.
- * @return
- */
- protected boolean isConnected(@Nullable String ssid, @Nullable String bssid) {
- WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- if (wifiInfo == null) {
- Log.e(TAG, "Failed to get WifiInfo");
- return false;
- }
- if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) return false;
- if (ssid != null && !wifiInfo.getSSID().equals(ssid)) return false;
- if (bssid != null && !wifiInfo.getBSSID().equals(bssid)) return false;
- return true;
- }
-
- /**
* Tear down the test case. Executed after test finishes - whether on success or failure.
*/
protected void tearDown() {
@@ -147,7 +124,7 @@
} catch (Exception e) {
Log.e(TAG, "Execute failed", e);
mListener.onTestFailed(
- mContext.getString(R.string.aware_unexpected_error));
+ mContext.getString(R.string.wifi_unexpected_error));
} finally {
tearDown();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/TestUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/TestUtils.java
new file mode 100644
index 0000000..2b7b4b1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/TestUtils.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.cts.verifier.R;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test utility methods.
+ */
+public class TestUtils {
+ private static final String TAG = "NetworkRequestTestCase";
+ private static final boolean DBG = true;
+ private static final int SCAN_TIMEOUT_MS = 30_000;
+
+ private final Context mContext;
+ protected BaseTestCase.Listener mListener;
+ private final WifiManager mWifiManager;
+
+ public TestUtils(Context context, BaseTestCase.Listener listener) {
+ mContext = context;
+ mListener = listener;
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ }
+
+ private boolean startScanAndWaitForResults() throws InterruptedException {
+ IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ // Scan Results available broadcast receiver.
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DBG) Log.v(TAG, "Broadcast onReceive " + intent);
+ if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return;
+ if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return;
+ if (DBG) Log.v(TAG, "Scan results received");
+ countDownLatch.countDown();
+ }
+ };
+ // Register the receiver for scan results broadcast.
+ mContext.registerReceiver(broadcastReceiver, intentFilter);
+
+ // Start scan.
+ if (DBG) Log.v(TAG, "Starting scan");
+ mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan));
+ if (!mWifiManager.startScan()) {
+ Log.e(TAG, "Failed to start scan");
+ // Unregister the receiver for scan results broadcast.
+ mContext.unregisterReceiver(broadcastReceiver);
+ return false;
+ }
+ // Wait for scan results.
+ if (DBG) Log.v(TAG, "Wait for scan results");
+ if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ Log.e(TAG, "No new scan results available");
+ // Unregister the receiver for scan results broadcast.
+ mContext.unregisterReceiver(broadcastReceiver);
+ return false;
+ }
+
+ // Unregister the receiver for scan results broadcast.
+ mContext.unregisterReceiver(broadcastReceiver);
+ return true;
+ }
+
+ // Helper to check if the scan result corresponds to an open network.
+ private static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) {
+ String capabilities = scanResult.capabilities;
+ return !capabilities.contains("PSK") && !capabilities.contains("EAP")
+ && !capabilities.contains("WEP") && !capabilities.contains("SAE")
+ && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE");
+ }
+
+ /**
+ * Helper method to start a scan and find any open networks in the scan results returned by the
+ * device.
+ * @return ScanResult instance corresponding to an open network if one exists, null if the
+ * scan failed or if there are no open networks found.
+ */
+ public @Nullable ScanResult startScanAndFindAnyOpenNetworkInResults()
+ throws InterruptedException {
+ // Start scan and wait for new results.
+ if (!startScanAndWaitForResults()) {
+ Log.e(TAG,"Failed to initiate a new scan. Using cached results from device");
+ }
+ // Filter results to find an open network.
+ List<ScanResult> scanResults = mWifiManager.getScanResults();
+ for (ScanResult scanResult : scanResults) {
+ if (!TextUtils.isEmpty(scanResult.SSID)
+ && !TextUtils.isEmpty(scanResult.BSSID)
+ && isScanResultForOpenNetwork(scanResult)) {
+ if (DBG) Log.v(TAG, "Found open network " + scanResult);
+ return scanResult;
+ }
+ }
+ Log.e(TAG, "No open networks found in scan results");
+ return null;
+ }
+
+ /**
+ * Helper method to check if a scan result with the specified SSID & BSSID matches the scan
+ * results returned by the device.
+ *
+ * @param ssid SSID of the network.
+ * @param bssid BSSID of network.
+ * @return true if there is a match, false otherwise.
+ */
+ public boolean findNetworkInScanResultsResults(@NonNull String ssid, @NonNull String bssid) {
+ List<ScanResult> scanResults = mWifiManager.getScanResults();
+ for (ScanResult scanResult : scanResults) {
+ if (TextUtils.equals(scanResult.SSID, ssid)
+ && TextUtils.equals(scanResult.BSSID, bssid)) {
+ if (DBG) Log.v(TAG, "Found network " + scanResult);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether the device is connected.
+ *
+ * @param ssid If ssid is specified, then check where the device is connected to a network
+ * with the specified SSID.
+ * @param bssid If bssid is specified, then check where the device is connected to a network
+ * with the specified BSSID.
+ * @return true if the device is connected to a network with the specified params, false
+ * otherwise.
+ */
+ public boolean isConnected(@Nullable String ssid, @Nullable String bssid) {
+ WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ if (wifiInfo == null) {
+ Log.e(TAG, "Failed to get WifiInfo");
+ return false;
+ }
+ if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) return false;
+ if (ssid != null && !wifiInfo.getSSID().equals(ssid)) return false;
+ if (bssid != null && !wifiInfo.getBSSID().equals(bssid)) return false;
+ return true;
+ }
+
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
index 528f7d6..b27407c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
@@ -21,21 +21,16 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSpecifier;
import android.os.PatternMatcher;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -45,9 +40,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
* Test case for all {@link NetworkRequest} requests with specifier built using
@@ -60,7 +52,6 @@
private static final String UNAVAILABLE_SSID = "blahblahblah";
private static final int NETWORK_REQUEST_TIMEOUT_MS = 30_000;
private static final int CALLBACK_TIMEOUT_MS = 40_000;
- private static final int SCAN_TIMEOUT_MS = 30_000;
public static final int NETWORK_SPECIFIER_SPECIFIC_SSID_BSSID = 0;
public static final int NETWORK_SPECIFIER_PATTERN_SSID_BSSID = 1;
@@ -80,7 +71,6 @@
private ConnectivityManager mConnectivityManager;
private NetworkRequest mNetworkRequest;
private CallbackUtils.NetworkCallback mNetworkCallback;
- private BroadcastReceiver mBroadcastReceiver;
private String mFailureReason;
public NetworkRequestTestCase(Context context, @NetworkSpecifierType int networkSpecifierType) {
@@ -107,7 +97,7 @@
case NETWORK_SPECIFIER_UNAVAILABLE_SSID_BSSID:
String ssid = UNAVAILABLE_SSID;
MacAddress bssid = MacAddress.createRandomUnicastAddress();
- if (findNetworkInScanResultsResults(ssid, bssid.toString())) {
+ if (mTestUtils.findNetworkInScanResultsResults(ssid, bssid.toString())) {
Log.e(TAG, "The specifiers chosen match a network in scan results."
+ "Test will fail");
return null;
@@ -121,82 +111,6 @@
return configBuilder.build();
}
- private boolean startScanAndWaitForResults() throws InterruptedException {
- IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- final CountDownLatch countDownLatch = new CountDownLatch(1);
- // Scan Results available broadcast receiver.
- mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DBG) Log.v(TAG, "Broadcast onReceive " + intent);
- if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return;
- if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return;
- if (DBG) Log.v(TAG, "Scan results received");
- countDownLatch.countDown();
- }
- };
- // Register the receiver for scan results broadcast.
- mContext.registerReceiver(mBroadcastReceiver, intentFilter);
-
- // Start scan.
- if (DBG) Log.v(TAG, "Starting scan");
- mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan));
- if (!mWifiManager.startScan()) {
- Log.e(TAG, "Failed to start scan");
- setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
- return false;
- }
- // Wait for scan results.
- if (DBG) Log.v(TAG, "Wait for scan results");
- if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- Log.e(TAG, "No new scan results available");
- setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
- return false;
- }
- return true;
- }
-
- // Helper to check if the scan result corresponds to an open network.
- private static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) {
- String capabilities = scanResult.capabilities;
- return !capabilities.contains("PSK") && !capabilities.contains("EAP")
- && !capabilities.contains("WEP") && !capabilities.contains("SAE")
- && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE");
- }
-
- private @Nullable ScanResult startScanAndFindAnyOpenNetworkInResults()
- throws InterruptedException {
- // Start scan and wait for new results.
- if (!startScanAndWaitForResults()) {
- return null;
- }
- // Filter results to find an open network.
- List<ScanResult> scanResults = mWifiManager.getScanResults();
- for (ScanResult scanResult : scanResults) {
- if (!TextUtils.isEmpty(scanResult.SSID)
- && !TextUtils.isEmpty(scanResult.BSSID)
- && isScanResultForOpenNetwork(scanResult)) {
- if (DBG) Log.v(TAG, "Found open network " + scanResult);
- return scanResult;
- }
- }
- Log.e(TAG, "No open networks found in scan results");
- setFailureReason(mContext.getString(R.string.wifi_status_open_network_not_found));
- return null;
- }
-
- private boolean findNetworkInScanResultsResults(@NonNull String ssid, @NonNull String bssid)
- throws InterruptedException {
- List<ScanResult> scanResults = mWifiManager.getScanResults();
- for (ScanResult scanResult : scanResults) {
- if (TextUtils.equals(scanResult.SSID, ssid)
- && TextUtils.equals(scanResult.BSSID, bssid)) {
- if (DBG) Log.v(TAG, "Found network " + scanResult);
- return true;
- }
- }
- return false;
- }
private void setFailureReason(String reason) {
synchronized (mLock) {
@@ -208,8 +122,11 @@
protected boolean executeTest() throws InterruptedException {
// Step 1: Scan and find any open network around.
if (DBG) Log.v(TAG, "Scan and find an open network");
- ScanResult openNetwork = startScanAndFindAnyOpenNetworkInResults();
- if (openNetwork == null) return false;
+ ScanResult openNetwork = mTestUtils.startScanAndFindAnyOpenNetworkInResults();
+ if (openNetwork == null) {
+ setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
+ return false;
+ }
// Step 2: Create a specifier for the chosen open network depending on the type of test.
NetworkSpecifier wns = createNetworkSpecifier(openNetwork);
@@ -287,9 +204,6 @@
@Override
protected void tearDown() {
- if (mBroadcastReceiver != null) {
- mContext.unregisterReceiver(mBroadcastReceiver);
- }
if (mNetworkCallback != null) {
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
index 4d0cbc5..f8cf306 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
@@ -20,7 +20,6 @@
import static android.net.wifi.WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -32,7 +31,6 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSuggestion;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -54,7 +52,6 @@
private static final boolean DBG = true;
private static final int CALLBACK_TIMEOUT_MS = 40_000;
- private static final int SCAN_TIMEOUT_MS = 30_000;
private final Object mLock = new Object();
private final List<WifiNetworkSuggestion> mNetworkSuggestions = new ArrayList<>();
@@ -88,73 +85,6 @@
return builder.build();
}
- private boolean startScanAndWaitForResults() throws InterruptedException {
- IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- final CountDownLatch countDownLatch = new CountDownLatch(1);
- // Scan Results available broadcast receiver.
- mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DBG) Log.v(TAG, "Broadcast onReceive " + intent);
- if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return;
- if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return;
- if (DBG) Log.v(TAG, "Scan results received");
- countDownLatch.countDown();
- }
- };
- // Register the receiver for scan results broadcast.
- mContext.registerReceiver(mBroadcastReceiver, intentFilter);
-
- // Start scan.
- if (DBG) Log.v(TAG, "Starting scan");
- mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan));
- if (!mWifiManager.startScan()) {
- Log.e(TAG, "Failed to start scan");
- setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
- return false;
- }
- // Wait for scan results.
- if (DBG) Log.v(TAG, "Wait for scan results");
- if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- Log.e(TAG, "No new scan results available");
- setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
- return false;
- }
- // Unregister the scan receiver.
- mContext.unregisterReceiver(mBroadcastReceiver);
- mBroadcastReceiver = null;
- return true;
- }
-
- // Helper to check if the scan result corresponds to an open network.
- private static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) {
- String capabilities = scanResult.capabilities;
- return !capabilities.contains("PSK") && !capabilities.contains("EAP")
- && !capabilities.contains("WEP") && !capabilities.contains("SAE")
- && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE");
- }
-
- private @Nullable ScanResult startScanAndFindAnyOpenNetworkInResults()
- throws InterruptedException {
- // Start scan and wait for new results.
- if (!startScanAndWaitForResults()) {
- return null;
- }
- // Filter results to find an open network.
- List<ScanResult> scanResults = mWifiManager.getScanResults();
- for (ScanResult scanResult : scanResults) {
- if (!TextUtils.isEmpty(scanResult.SSID)
- && !TextUtils.isEmpty(scanResult.BSSID)
- && isScanResultForOpenNetwork(scanResult)) {
- if (DBG) Log.v(TAG, "Found open network " + scanResult);
- return scanResult;
- }
- }
- Log.e(TAG, "No open networks found in scan results");
- setFailureReason(mContext.getString(R.string.wifi_status_open_network_not_found));
- return null;
- }
-
private void setFailureReason(String reason) {
synchronized (mLock) {
mFailureReason = reason;
@@ -165,8 +95,11 @@
protected boolean executeTest() throws InterruptedException {
// Step 1: Scan and find any open network around.
if (DBG) Log.v(TAG, "Scan and find an open network");
- ScanResult openNetwork = startScanAndFindAnyOpenNetworkInResults();
- if (openNetwork == null) return false;
+ ScanResult openNetwork = mTestUtils.startScanAndFindAnyOpenNetworkInResults();
+ if (openNetwork == null) {
+ setFailureReason(mContext.getString(R.string.wifi_status_scan_failure));
+ return false;
+ }
// Step 1.a (Optional): Register for the post connection broadcast.
final CountDownLatch countDownLatchForPostConnectionBcast = new CountDownLatch(1);
@@ -225,7 +158,7 @@
// Step 6: Ensure that we connected to the suggested network (optionally, the correct
// BSSID).
- if (!isConnected("\"" + openNetwork.SSID + "\"",
+ if (!mTestUtils.isConnected("\"" + openNetwork.SSID + "\"",
// TODO: This might fail if there are other BSSID's for the same network & the
// device decided to connect/roam to a different BSSID. We don't turn off roaming
// for suggestions.
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
similarity index 100%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivityLauncher.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
similarity index 91%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
index d844894..3e6a02c 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
+++ b/common/device-side/util/src/android/contentcaptureservice/cts/common/ActivityLauncher.java
@@ -25,6 +25,8 @@
/**
* Helper used to launch an activity and watch for its lifecycle events.
+ *
+ * @param <A> activity type
*/
public final class ActivityLauncher<A extends Activity> {
@@ -39,11 +41,17 @@
mLaunchIntent = new Intent(context, activityClass);
}
+ /**
+ * Gets a watcher for the activity lifecycle events.
+ */
@NonNull
public ActivityWatcher getWatcher() {
return mWatcher;
}
+ /**
+ * Launches the activity.
+ */
@NonNull
public A launchActivity() {
return mActivityTestRule.launchActivity(mLaunchIntent);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/DoubleVisitor.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/DoubleVisitor.java
similarity index 100%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/DoubleVisitor.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/DoubleVisitor.java
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/Visitor.java b/common/device-side/util/src/android/contentcaptureservice/cts/common/Visitor.java
similarity index 100%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/Visitor.java
rename to common/device-side/util/src/android/contentcaptureservice/cts/common/Visitor.java
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
deleted file mode 100644
index d12caa8..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
+++ /dev/null
@@ -1,54 +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.compatibility.common.util;
-
-import org.junit.Before;
-
-/**
- * Device-side base class for tests leveraging the Business Logic service for rules that are
- * conditionally added based on the device characteristics.
- */
-public class BusinessLogicConditionalTestCase extends BusinessLogicTestCase {
-
- @Override
- @Before
- public void handleBusinessLogic() {
- super.loadBusinessLogic();
- ensureAuthenticated();
- super.executeBusinessLogic();
- }
-
- protected void ensureAuthenticated() {
- if (!mCanReadBusinessLogic) {
- // super class handles the condition that the service is unavailable.
- return;
- }
-
- if (!mBusinessLogic.mConditionalTestsEnabled) {
- skipTest("Execution of device specific tests is not enabled. "
- + "Enable with '--conditional-business-logic-tests-enabled'");
- }
-
- if (mBusinessLogic.isAuthorized()) {
- // Run test as normal.
- return;
- }
- String message = mBusinessLogic.getAuthenticationStatusMessage();
-
- // Fail test since request was not authorized.
- failTest(String.format("Unable to execute because %s.", message));
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
index 671d33b..29607c3 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
@@ -51,6 +51,7 @@
@Before
public void handleBusinessLogic() {
loadBusinessLogic();
+ ensureAuthenticated();
executeBusinessLogic();
}
@@ -79,6 +80,27 @@
}
}
+ protected void ensureAuthenticated() {
+ if (!mCanReadBusinessLogic) {
+ // super class handles the condition that the service is unavailable.
+ return;
+ }
+
+ if (!mBusinessLogic.mConditionalTestsEnabled) {
+ skipTest("Execution of device specific tests is not enabled. "
+ + "Enable with '--conditional-business-logic-tests-enabled'");
+ }
+
+ if (mBusinessLogic.isAuthorized()) {
+ // Run test as normal.
+ return;
+ }
+ String message = mBusinessLogic.getAuthenticationStatusMessage();
+
+ // Fail test since request was not authorized.
+ failTest(String.format("Unable to execute because %s.", message));
+ }
+
protected static Instrumentation getInstrumentation() {
return InstrumentationRegistry.getInstrumentation();
}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
index eee05e2..a4359fd 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
@@ -59,7 +59,10 @@
};
}
- private static boolean hasService(@NonNull String service) {
+ /**
+ * Checks if the device has the given service.
+ */
+ public static boolean hasService(@NonNull String service) {
// TODO: ideally should call SystemServiceManager directly, but we would need to open
// some @Testing APIs for that.
String command = "service check " + service;
diff --git a/hostsidetests/abioverride/AndroidTest.xml b/hostsidetests/abioverride/AndroidTest.xml
index 99f731c..be3e818 100644
--- a/hostsidetests/abioverride/AndroidTest.xml
+++ b/hostsidetests/abioverride/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS AbiOverride host test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="webview" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAbiOverrideTestApp.apk" />
diff --git a/hostsidetests/angle/AndroidTest.xml b/hostsidetests/angle/AndroidTest.xml
index c72618a..140da70 100644
--- a/hostsidetests/angle/AndroidTest.xml
+++ b/hostsidetests/angle/AndroidTest.xml
@@ -17,6 +17,8 @@
<configuration description="Config for CtsAngleIntegrationHostTestCases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="graphics" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAngleDriverTestCases.apk" />
diff --git a/hostsidetests/angle/app/driverTest/Android.mk b/hostsidetests/angle/app/driverTest/Android.mk
index 37a1140..114214e 100644
--- a/hostsidetests/angle/app/driverTest/Android.mk
+++ b/hostsidetests/angle/app/driverTest/Android.mk
@@ -27,7 +27,7 @@
LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
+LOCAL_COMPATIBILITY_SUITE := cts vts cts_instant
LOCAL_MULTILIB := both
diff --git a/hostsidetests/angle/app/driverTest/AndroidManifest.xml b/hostsidetests/angle/app/driverTest/AndroidManifest.xml
index be800a1..28bcb11 100755
--- a/hostsidetests/angle/app/driverTest/AndroidManifest.xml
+++ b/hostsidetests/angle/app/driverTest/AndroidManifest.xml
@@ -16,7 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.angleIntegrationTest.driverTest">
+ package="com.android.angleIntegrationTest.driverTest"
+ android:targetSandboxVersion="2">
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/angle/app/driverTestSecondary/Android.mk b/hostsidetests/angle/app/driverTestSecondary/Android.mk
index d361192..760a892 100644
--- a/hostsidetests/angle/app/driverTestSecondary/Android.mk
+++ b/hostsidetests/angle/app/driverTestSecondary/Android.mk
@@ -27,7 +27,7 @@
LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
+LOCAL_COMPATIBILITY_SUITE := cts vts cts_instant
LOCAL_MULTILIB := both
diff --git a/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml b/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml
index bd2739d..5a92e96 100755
--- a/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml
+++ b/hostsidetests/angle/app/driverTestSecondary/AndroidManifest.xml
@@ -16,7 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.angleIntegrationTest.driverTestSecondary">
+ package="com.android.angleIntegrationTest.driverTestSecondary"
+ android:targetSandboxVersion="2">
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
index efb4bce..73946e0 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
@@ -19,6 +19,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := test_current
LOCAL_STATIC_JAVA_LIBRARIES := \
+ compatibility-device-util \
android-support-test \
ub-uiautomator
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
index fa1ca7b..7d84684 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
@@ -16,6 +16,8 @@
package com.android.cts.mediastorageapp;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -45,7 +47,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
@@ -53,11 +54,13 @@
public class MediaStorageTest {
private Context mContext;
private ContentResolver mContentResolver;
+ private int mUserId;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mContentResolver = mContext.getContentResolver();
+ mUserId = mContext.getUserId();
}
@Test
@@ -65,7 +68,7 @@
final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
- clearMediaOwner(blue);
+ clearMediaOwner(blue, mUserId);
// Since we have no permissions, we should only be able to see media
// that we've contributed
@@ -97,7 +100,7 @@
final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
- clearMediaOwner(blue);
+ clearMediaOwner(blue, mUserId);
// Holding read permission we can see items we don't own
final HashSet<Long> seen = new HashSet<>();
@@ -126,7 +129,7 @@
final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
- clearMediaOwner(blue);
+ clearMediaOwner(blue, mUserId);
// Holding read permission we can see items we don't own
final HashSet<Long> seen = new HashSet<>();
@@ -151,7 +154,7 @@
@Test
public void testMediaEscalation() throws Exception {
final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
- clearMediaOwner(red);
+ clearMediaOwner(red, mUserId);
// Confirm that we get can take action to get write access
RecoverableSecurityException exception = null;
@@ -204,12 +207,10 @@
}
}
- private static void clearMediaOwner(Uri uri) throws IOException {
- try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
- InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
- "content update --uri " + uri + " --bind owner_package_name:n:"))) {
- while (is.read() != -1) {
- }
- }
+ private static void clearMediaOwner(Uri uri, int userId) throws IOException {
+ final String cmd = String.format(
+ "content update --uri %s --user %d --bind owner_package_name:n:",
+ uri, userId);
+ runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
}
}
diff --git a/hostsidetests/atrace/AndroidTest.xml b/hostsidetests/atrace/AndroidTest.xml
index ecaa17a..d616f90 100644
--- a/hostsidetests/atrace/AndroidTest.xml
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS atrace host test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsAtraceHostTestCases.jar" />
<option name="runtime-hint" value="9m" />
diff --git a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
index cb57d14..06253cd 100644
--- a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
+++ b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.atracetestapp">
+ package="com.android.cts.atracetestapp"
+ android:targetSandboxVersion="2">
<!--
A simple app with a tracing section to test that apps tracing signals are
emitted by atrace.
diff --git a/hostsidetests/compilation/AndroidTest.xml b/hostsidetests/compilation/AndroidTest.xml
index fe17ac8..d2c6f87 100644
--- a/hostsidetests/compilation/AndroidTest.xml
+++ b/hostsidetests/compilation/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS Compilation Test">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="art" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsCompilationTestCases.jar" />
<option name="runtime-hint" value="9m45s" />
diff --git a/hostsidetests/compilation/TEST_MAPPING b/hostsidetests/compilation/TEST_MAPPING
new file mode 100644
index 0000000..cdaa108
--- /dev/null
+++ b/hostsidetests/compilation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsCompilationTestCases"
+ }
+ ]
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
index 1d6105d..72bebcf 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
@@ -20,6 +20,7 @@
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -29,7 +30,9 @@
import android.support.test.uiautomator.UiDevice;
import android.util.Log;
+import org.junit.After;
import org.junit.Before;
+import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +48,8 @@
private static final String TAG = LockTaskHostDrivenTest.class.getName();
+ private static final int ACTIVITY_RESUMED_TIMEOUT_MILLIS = 20000; // 20 seconds
+
private static final String LOCK_TASK_ACTIVITY
= LockTaskUtilityActivityIfWhitelisted.class.getName();
@@ -53,14 +58,45 @@
private ActivityManager mActivityManager;
private DevicePolicyManager mDevicePolicyManager;
+ private volatile boolean mIsActivityResumed;
+ private final Object mActivityResumedLock = new Object();
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "onReceive: " + action);
+ if (LockTaskUtilityActivity.RESUME_ACTION.equals(action)) {
+ synchronized (mActivityResumedLock) {
+ mIsActivityResumed = true;
+ mActivityResumedLock.notify();
+ }
+ } else if (LockTaskUtilityActivity.PAUSE_ACTION.equals(action)) {
+ synchronized (mActivityResumedLock) {
+ mIsActivityResumed = false;
+ mActivityResumedLock.notify();
+ }
+ }
+ }
+ };
+
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
mActivityManager = mContext.getSystemService(ActivityManager.class);
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(LockTaskUtilityActivity.RESUME_ACTION);
+ filter.addAction(LockTaskUtilityActivity.PAUSE_ACTION);
+ mContext.registerReceiver(mReceiver, filter);
}
+ @After
+ public void tearDown() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
@Test
public void startLockTask() throws Exception {
Log.d(TAG, "startLockTask on host-driven test (no cleanup)");
@@ -77,6 +113,13 @@
public void testLockTaskIsActiveAndCantBeInterrupted() throws Exception {
mUiDevice.waitForIdle();
+ // We need to wait until the LockTaskActivity is ready
+ // since com.android.cts.deviceowner can be killed by AMS for reason "start instr".
+ synchronized (mActivityResumedLock) {
+ if (!mIsActivityResumed) {
+ mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+ }
+ }
checkLockedActivityIsRunning();
mUiDevice.pressBack();
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
index 8e51bc3..3dd79c8 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
@@ -135,4 +135,26 @@
DUMMY_PRIVATE_DNS_HOST,
DevicePolicyManager.PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING);
}
+
+ public void testCanSetModeDespiteUserRestriction() {
+ // First set a specific host and assert that applied.
+ callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+ VALID_PRIVATE_DNS_HOST,
+ DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS);
+ assertThat(
+ mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isEqualTo(
+ PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+
+ // Set a user restriction
+ setUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS, true);
+
+ // Next, set the mode to automatic and confirm that has applied.
+ callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_OPPORTUNISTIC, null,
+ DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS);
+
+ assertThat(
+ mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isEqualTo(
+ PRIVATE_DNS_MODE_OPPORTUNISTIC);
+ assertThat(mDevicePolicyManager.getGlobalPrivateDnsHost(getWho())).isNull();
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
index 803ae3f..fd9a0d6 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
@@ -49,18 +49,42 @@
super.tearDown();
}
- public void testQuietMode() throws Exception {
+ public void testQuietMode_defaultForegroundLauncher() throws Exception {
if (!mHasFeature) {
return;
}
runDeviceTestsAsUser(
TEST_PACKAGE,
TEST_CLASS,
- null,
+ "testTryEnableQuietMode_defaultForegroundLauncher",
mPrimaryUserId,
createParams(mProfileId));
}
+ public void testQuietMode_notForegroundLauncher() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ runDeviceTestsAsUser(
+ TEST_PACKAGE,
+ TEST_CLASS,
+ "testTryEnableQuietMode_notForegroundLauncher",
+ mPrimaryUserId,
+ createParams(mProfileId));
+ }
+
+ public void testQuietMode_notDefaultLauncher() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ runDeviceTestsAsUser(
+ TEST_PACKAGE,
+ TEST_CLASS,
+ "testTryEnableQuietMode_notDefaultLauncher",
+ mPrimaryUserId,
+ createParams(mProfileId));
+ }
+
private void createAndStartManagedProfile() throws Exception {
mProfileId = createManagedProfile(mPrimaryUserId);
switchUser(mPrimaryUserId);
diff --git a/hostsidetests/gputools/Android.mk b/hostsidetests/gputools/Android.mk
index b2946be..7f1d242 100644
--- a/hostsidetests/gputools/Android.mk
+++ b/hostsidetests/gputools/Android.mk
@@ -20,7 +20,7 @@
LOCAL_MODULE_TAGS := tests
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts cts_instant
LOCAL_MODULE := CtsGpuToolsHostTestCases
diff --git a/hostsidetests/gputools/AndroidTest.xml b/hostsidetests/gputools/AndroidTest.xml
index 199f5e7..53419cd 100644
--- a/hostsidetests/gputools/AndroidTest.xml
+++ b/hostsidetests/gputools/AndroidTest.xml
@@ -17,6 +17,8 @@
<configuration description="Config for CtsGpuToolsHostTestCases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="graphics" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsGpuToolsRootlessGpuDebugApp-DEBUG.apk" />
diff --git a/hostsidetests/gputools/apps/Android.mk b/hostsidetests/gputools/apps/Android.mk
index 138b4e9..0f2760a 100644
--- a/hostsidetests/gputools/apps/Android.mk
+++ b/hostsidetests/gputools/apps/Android.mk
@@ -34,7 +34,7 @@
LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts cts_instant
LOCAL_MULTILIB := both
@@ -45,7 +45,8 @@
--rename-manifest-package android.rootlessgpudebug.DEBUG.app \
--debug-mode
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
@@ -68,6 +69,8 @@
LOCAL_AAPT_FLAGS := \
--rename-manifest-package android.rootlessgpudebug.RELEASE.app
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/gputools/apps/AndroidManifest.xml b/hostsidetests/gputools/apps/AndroidManifest.xml
index fab44c3..0e033f3 100755
--- a/hostsidetests/gputools/apps/AndroidManifest.xml
+++ b/hostsidetests/gputools/apps/AndroidManifest.xml
@@ -16,7 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.rootlessgpudebug.app">>
+ package="android.rootlessgpudebug.app"
+ android:targetSandboxVersion="2">
<application android:extractNativeLibs="true" >
<activity android:name=".RootlessGpuDebugDeviceActivity" >
diff --git a/hostsidetests/gputools/layers/Android.mk b/hostsidetests/gputools/layers/Android.mk
index f91b0d3..29e832f 100644
--- a/hostsidetests/gputools/layers/Android.mk
+++ b/hostsidetests/gputools/layers/Android.mk
@@ -89,7 +89,7 @@
LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts cts_instant
LOCAL_MULTILIB := both
@@ -101,6 +101,8 @@
libGLES_glesLayer2 \
libGLES_glesLayer3
-include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/gputools/layers/AndroidManifest.xml b/hostsidetests/gputools/layers/AndroidManifest.xml
index 2b187ad..6b58238 100755
--- a/hostsidetests/gputools/layers/AndroidManifest.xml
+++ b/hostsidetests/gputools/layers/AndroidManifest.xml
@@ -16,7 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.rootlessgpudebug.LAYERS.app">
+ package="android.rootlessgpudebug.LAYERS.app"
+ android:targetSandboxVersion="2">
<application android:extractNativeLibs="true" android:debuggable="false"
android:hasCode="false">
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index a3e51e1..2a0ee1e 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -207,6 +207,10 @@
apkIn.close();
}
+ // If this assert fires , try increasing the timeout
+ Assert.assertTrue("Log scanning did not complete before timout (" +
+ LOG_SEARCH_TIMEOUT_MS + "ms)", scanComplete);
+
return result;
}
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
index 365f792..73d4b84 100644
--- a/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
+++ b/hostsidetests/inputmethodservice/deviceside/provider/Android.mk
@@ -36,6 +36,6 @@
LOCAL_PACKAGE_NAME := CtsInputMethodServiceEventProvider
LOCAL_SDK_VERSION := test_current
-LOCAL_MIN_SDK_VERSION := 19
+LOCAL_MIN_SDK_VERSION := 26
include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml b/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml
index 9189da3..841b7c1 100755
--- a/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml
+++ b/hostsidetests/inputmethodservice/deviceside/provider/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.inputmethodservice.cts.provider">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="25" />
+ <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26" />
<application android:label="CtsInputMethodServiceEventProvider">
<provider
diff --git a/hostsidetests/sample/AndroidTest.xml b/hostsidetests/sample/AndroidTest.xml
index 5539166..0368682 100644
--- a/hostsidetests/sample/AndroidTest.xml
+++ b/hostsidetests/sample/AndroidTest.xml
@@ -16,7 +16,7 @@
<configuration description="Config for CTS Sample host test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="misc" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSampleDeviceApp.apk" />
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 410d01f..abb293b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -544,6 +544,7 @@
if (statsdDisabled()) {
return;
}
+ if (!hasFeature(FEATURE_WATCH, false)) return;
final int atomTag = Atom.OVERLAY_STATE_CHANGED_FIELD_NUMBER;
Set<Integer> entered = new HashSet<>(
@@ -1112,7 +1113,7 @@
}
// Make device side test package a role holder
- String callScreenAppRole = "android.app.role.CALL_SCREENING_APP";
+ String callScreenAppRole = "android.app.role.CALL_SCREENING";
getDevice().executeShellCommand(
"cmd role add-role-holder " + callScreenAppRole + " " + DEVICE_SIDE_TEST_PACKAGE);
diff --git a/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java b/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java
index e8515d9..4b26ca9 100644
--- a/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java
+++ b/hostsidetests/systemui/app/src/android/systemui/cts/TestTileService.java
@@ -54,6 +54,7 @@
@Override
public void onTileAdded() {
Log.i(TAG, TEST_PREFIX + "onTileAdded");
+ super.onTileAdded();
}
@Override
diff --git a/hostsidetests/theme/app/src/android/theme/app/ConditionCheck.java b/hostsidetests/theme/app/src/android/theme/app/ConditionCheck.java
new file mode 100644
index 0000000..8954a8d
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/ConditionCheck.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.theme.app;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Runnable that re-posts itself on a handler until either all of the conditions are satisfied
+ * or a retry threshold is exceeded.
+ */
+class ConditionCheck implements Runnable {
+ private static final int MAX_RETRIES = 3;
+ private static final int RETRY_DELAY = 500;
+
+ private final Handler mHandler;
+ private final Runnable mOnSuccess;
+ private final Consumer<String> mOnFailure;
+ private final ArrayList<Pair<String, Supplier<Boolean>>> mConditions = new ArrayList<>();
+
+ private ArrayList<Pair<String, Supplier<Boolean>>> mRemainingConditions = new ArrayList<>();
+ private int mRemainingRetries;
+
+ ConditionCheck(Context context, Runnable onSuccess, Consumer<String> onFailure) {
+ mHandler = new Handler(context.getMainLooper());
+ mOnSuccess = onSuccess;
+ mOnFailure = onFailure;
+ }
+
+ public ConditionCheck addCondition(String summary, Supplier<Boolean> condition) {
+ mConditions.add(new Pair<>(summary, condition));
+ return this;
+ }
+
+ public void start() {
+ mRemainingConditions = new ArrayList<>(mConditions);
+ mRemainingRetries = 0;
+
+ mHandler.removeCallbacks(this);
+ mHandler.post(this);
+ }
+
+ public void cancel() {
+ mHandler.removeCallbacks(this);
+ }
+
+ @Override
+ public void run() {
+ mRemainingConditions.removeIf(condition -> condition.second.get());
+ if (mRemainingConditions.isEmpty()) {
+ mOnSuccess.run();
+ } else if (mRemainingRetries < MAX_RETRIES) {
+ mRemainingRetries++;
+ mHandler.removeCallbacks(this);
+ mHandler.postDelayed(this, RETRY_DELAY);
+ } else {
+ final StringBuffer buffer = new StringBuffer("Failed conditions:");
+ mRemainingConditions.forEach(condition ->
+ buffer.append("\n").append(condition.first));
+ mOnFailure.accept(buffer.toString());
+ }
+ }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
index 3591410..a41e426 100644
--- a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
@@ -16,27 +16,20 @@
package android.theme.app;
-import android.Manifest.permission;
+import static android.theme.app.TestConfiguration.THEMES;
+
import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Environment;
-import android.os.Handler;
import android.util.Log;
-import android.util.Pair;
import android.view.WindowManager.LayoutParams;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
/**
* Generates images by iterating through all themes and launching instances of
@@ -69,16 +62,9 @@
mOutputDir = setupOutputDirectory();
if (mOutputDir == null) {
finish("Failed to create output directory " + mOutputDir.getAbsolutePath(), false);
+ } else {
+ generateNextImage();
}
-
- // The activity has been created, but we don't want to start image generation until various
- // asynchronous conditions are satisfied.
- new ConditionCheck(this, () -> generateNextImage(), message -> finish(message, false))
- .addCondition("Device is unlocked",
- () -> !getSystemService(KeyguardManager.class).isDeviceLocked())
- .addCondition("Window is focused",
- () -> hasWindowFocus())
- .start();
}
private File setupOutputDirectory() {
@@ -93,63 +79,6 @@
}
/**
- * Runnable that re-posts itself on a handler until either all of the conditions are satisfied
- * or a retry threshold is exceeded.
- */
- class ConditionCheck implements Runnable {
- private static final int MAX_RETRIES = 3;
- private static final int RETRY_DELAY = 500;
-
- private final Handler mHandler;
- private final Runnable mOnSuccess;
- private final Consumer<String> mOnFailure;
- private final ArrayList<Pair<String, Supplier<Boolean>>> mConditions = new ArrayList<>();
-
- private ArrayList<Pair<String, Supplier<Boolean>>> mRemainingConditions = new ArrayList<>();
- private int mRemainingRetries;
-
- ConditionCheck(Context context, Runnable onSuccess, Consumer<String> onFailure) {
- mHandler = new Handler(context.getMainLooper());
- mOnSuccess = onSuccess;
- mOnFailure = onFailure;
- }
-
- public ConditionCheck addCondition(String summary, Supplier<Boolean> condition) {
- mConditions.add(new Pair<>(summary, condition));
- return this;
- }
-
- public void start() {
- mRemainingConditions = new ArrayList<>(mConditions);
- mRemainingRetries = 0;
-
- mHandler.removeCallbacks(this);
- mHandler.post(this);
- }
-
- public void cancel() {
- mHandler.removeCallbacks(this);
- }
-
- @Override
- public void run() {
- mRemainingConditions.removeIf(condition -> condition.second.get());
- if (mRemainingConditions.isEmpty()) {
- mOnSuccess.run();
- } else if (mRemainingRetries < MAX_RETRIES) {
- mRemainingRetries++;
- mHandler.removeCallbacks(this);
- mHandler.postDelayed(this, RETRY_DELAY);
- } else {
- final StringBuffer buffer = new StringBuffer("Failed conditions:");
- mRemainingConditions.forEach(condition ->
- buffer.append("\n").append(condition.first));
- mOnFailure.accept(buffer.toString());
- }
- }
- }
-
- /**
* @return whether the test finished successfully
*/
public boolean isFinishSuccess() {
@@ -167,8 +96,23 @@
/**
* Starts the activity to generate the next image.
*/
- private boolean generateNextImage() {
- final ThemeDeviceActivity.Theme theme = ThemeDeviceActivity.THEMES[mCurrentTheme];
+ private void generateNextImage() {
+ // Keep trying themes until one works.
+ boolean success = false;
+ while (++mCurrentTheme < THEMES.length && !success) {
+ success = launchThemeDeviceActivity();
+ }
+
+ // If we ran out of themes, we're done.
+ if (!success) {
+ compressOutput();
+
+ finish("Image generation complete!", true);
+ }
+ }
+
+ private boolean launchThemeDeviceActivity() {
+ final ThemeInfo theme = THEMES[mCurrentTheme];
if (theme.apiLevel > VERSION.SDK_INT) {
Log.v(TAG, "Skipping theme \"" + theme.name
+ "\" (requires API " + theme.apiLevel + ")");
@@ -193,18 +137,7 @@
return;
}
- // Keep trying themes until one works.
- boolean success = false;
- while (++mCurrentTheme < ThemeDeviceActivity.THEMES.length && !success) {
- success = generateNextImage();
- }
-
- // If we ran out of themes, we're done.
- if (!success) {
- compressOutput();
-
- finish("Image generation complete!", true);
- }
+ generateNextImage();
}
private void compressOutput() {
diff --git a/hostsidetests/theme/app/src/android/theme/app/LayoutInfo.java b/hostsidetests/theme/app/src/android/theme/app/LayoutInfo.java
new file mode 100644
index 0000000..e7beab7e
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/LayoutInfo.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.theme.app;
+
+import android.theme.app.modifiers.AbstractLayoutModifier;
+
+/**
+ * A class to encapsulate information about a layout.
+ */
+class LayoutInfo {
+ public final int id;
+ public final String name;
+ public final AbstractLayoutModifier modifier;
+
+ LayoutInfo(int id, String name) {
+ this(id, name, null);
+ }
+
+ LayoutInfo(int id, String name, AbstractLayoutModifier modifier) {
+ this.id = id;
+ this.name = name;
+ this.modifier = modifier;
+ }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/LayoutModifier.java b/hostsidetests/theme/app/src/android/theme/app/LayoutModifier.java
deleted file mode 100644
index e007129..0000000
--- a/hostsidetests/theme/app/src/android/theme/app/LayoutModifier.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.theme.app;
-
-import android.view.View;
-
-/**
- * Interface used to do further setup on a view after it has been inflated.
- */
-public interface LayoutModifier {
-
- /**
- * Modifies the view before it has been added to a parent. Useful for avoiding animations in
- * response to setter calls.
- *
- * @param view the view inflated by the test activity
- */
- void modifyViewBeforeAdd(View view);
-
- /**
- * Modifies the view after it has been added to a parent. Useful for running animations in
- * response to setter calls.
- *
- * @param view the view inflated by the test activity
- */
- void modifyViewAfterAdd(View view);
-}
diff --git a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
new file mode 100644
index 0000000..d6c9f1c
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.theme.app;
+
+import android.os.Build;
+import android.theme.app.modifiers.DatePickerModifier;
+import android.theme.app.modifiers.ProgressBarModifier;
+import android.theme.app.modifiers.SearchViewModifier;
+import android.theme.app.modifiers.ViewCheckedModifier;
+import android.theme.app.modifiers.ViewPressedModifier;
+import android.theme.app.modifiers.TimePickerModifier;
+
+/**
+ * Constants defining the themes and layouts to be verified.
+ */
+public class TestConfiguration {
+ @SuppressWarnings("deprecation")
+ static final ThemeInfo[] THEMES = {
+ // Holo
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo,
+ Build.VERSION_CODES.HONEYCOMB, "holo"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog,
+ Build.VERSION_CODES.HONEYCOMB, "holo_dialog"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog_MinWidth,
+ Build.VERSION_CODES.HONEYCOMB, "holo_dialog_minwidth"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar,
+ Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar_MinWidth,
+ Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar_minwidth"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_DialogWhenLarge,
+ Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_DialogWhenLarge_NoActionBar,
+ Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge_noactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_InputMethod,
+ Build.VERSION_CODES.HONEYCOMB, "holo_inputmethod"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar,
+ Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar_Fullscreen,
+ Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar_fullscreen"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar_Overscan,
+ Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_noactionbar_overscan"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_NoActionBar_TranslucentDecor,
+ Build.VERSION_CODES.KITKAT, "holo_noactionbar_translucentdecor"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Panel,
+ Build.VERSION_CODES.HONEYCOMB, "holo_panel"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Wallpaper,
+ Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Wallpaper_NoTitleBar,
+ Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper_notitlebar"),
+
+ // Holo Light
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_DarkActionBar,
+ Build.VERSION_CODES.ICE_CREAM_SANDWICH, "holo_light_darkactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog_MinWidth,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_minwidth"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar_minwidth"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge_NoActionBar,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge_noactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar,
+ Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen,
+ Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar_fullscreen"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Overscan,
+ Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_light_noactionbar_overscan"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor,
+ Build.VERSION_CODES.KITKAT, "holo_light_noactionbar_translucentdecor"),
+ new ThemeInfo(ThemeInfo.HOLO, android.R.style.Theme_Holo_Light_Panel,
+ Build.VERSION_CODES.HONEYCOMB, "holo_light_panel"),
+
+ // Material
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material,
+ Build.VERSION_CODES.LOLLIPOP, "material"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialog"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_Alert,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialog_alert"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_MinWidth,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialog_minwidth"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar_MinWidth,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar_minwidth"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Dialog_Presentation,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialog_presentation"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge_NoActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge_noactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_InputMethod,
+ Build.VERSION_CODES.LOLLIPOP, "material_inputmethod"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_noactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar_Fullscreen,
+ Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_fullscreen"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar_Overscan,
+ Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_overscan"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_NoActionBar_TranslucentDecor,
+ Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_translucentdecor"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Panel,
+ Build.VERSION_CODES.LOLLIPOP, "material_panel"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Settings,
+ Build.VERSION_CODES.LOLLIPOP, "material_settings"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Voice,
+ Build.VERSION_CODES.LOLLIPOP, "material_voice"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Wallpaper,
+ Build.VERSION_CODES.LOLLIPOP, "material_wallpaper"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Wallpaper_NoTitleBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_wallpaper_notitlebar"),
+
+ // Material Light
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light,
+ Build.VERSION_CODES.LOLLIPOP, "material_light"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_DarkActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_darkactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialog"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Alert,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_alert"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_MinWidth,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_minwidth"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar_MinWidth,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar_minwidth"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Presentation,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_presentation"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge_NoActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge_noactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_LightStatusBar,
+ Build.VERSION_CODES.M, "material_light_lightstatusbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Fullscreen,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_fullscreen"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Overscan,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_overscan"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_TranslucentDecor,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_translucentdecor"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Panel,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_panel"),
+ new ThemeInfo(ThemeInfo.MATERIAL, android.R.style.Theme_Material_Light_Voice,
+ Build.VERSION_CODES.LOLLIPOP, "material_light_voice")
+ };
+
+ static final LayoutInfo[] LAYOUTS = {
+ new LayoutInfo(R.layout.button, "button"),
+ new LayoutInfo(R.layout.button, "button_pressed",
+ new ViewPressedModifier()),
+ new LayoutInfo(R.layout.checkbox, "checkbox"),
+ new LayoutInfo(R.layout.checkbox, "checkbox_checked",
+ new ViewCheckedModifier()),
+ new LayoutInfo(R.layout.chronometer, "chronometer"),
+ new LayoutInfo(R.layout.color_blue_bright, "color_blue_bright"),
+ new LayoutInfo(R.layout.color_blue_dark, "color_blue_dark"),
+ new LayoutInfo(R.layout.color_blue_light, "color_blue_light"),
+ new LayoutInfo(R.layout.color_green_dark, "color_green_dark"),
+ new LayoutInfo(R.layout.color_green_light, "color_green_light"),
+ new LayoutInfo(R.layout.color_orange_dark, "color_orange_dark"),
+ new LayoutInfo(R.layout.color_orange_light, "color_orange_light"),
+ new LayoutInfo(R.layout.color_purple, "color_purple"),
+ new LayoutInfo(R.layout.color_red_dark, "color_red_dark"),
+ new LayoutInfo(R.layout.color_red_light, "color_red_light"),
+ new LayoutInfo(R.layout.datepicker, "datepicker",
+ new DatePickerModifier()),
+ new LayoutInfo(R.layout.edittext, "edittext"),
+ new LayoutInfo(R.layout.progressbar_horizontal_0, "progressbar_horizontal_0"),
+ new LayoutInfo(R.layout.progressbar_horizontal_100, "progressbar_horizontal_100"),
+ new LayoutInfo(R.layout.progressbar_horizontal_50, "progressbar_horizontal_50"),
+ new LayoutInfo(R.layout.progressbar_large, "progressbar_large",
+ new ProgressBarModifier()),
+ new LayoutInfo(R.layout.progressbar_small, "progressbar_small",
+ new ProgressBarModifier()),
+ new LayoutInfo(R.layout.progressbar, "progressbar",
+ new ProgressBarModifier()),
+ new LayoutInfo(R.layout.radiobutton_checked, "radiobutton_checked"),
+ new LayoutInfo(R.layout.radiobutton, "radiobutton"),
+ new LayoutInfo(R.layout.radiogroup_horizontal, "radiogroup_horizontal"),
+ new LayoutInfo(R.layout.radiogroup_vertical, "radiogroup_vertical"),
+ new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0"),
+ new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5"),
+ new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5"),
+ new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0_pressed",
+ new ViewPressedModifier()),
+ new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
+ new ViewPressedModifier()),
+ new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5_pressed",
+ new ViewPressedModifier()),
+ new LayoutInfo(R.layout.searchview, "searchview_query",
+ new SearchViewModifier(SearchViewModifier.QUERY)),
+ new LayoutInfo(R.layout.searchview, "searchview_query_hint",
+ new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
+ new LayoutInfo(R.layout.seekbar_0, "seekbar_0"),
+ new LayoutInfo(R.layout.seekbar_100, "seekbar_100"),
+ new LayoutInfo(R.layout.seekbar_50, "seekbar_50"),
+ new LayoutInfo(R.layout.spinner, "spinner"),
+ new LayoutInfo(R.layout.switch_button_checked, "switch_button_checked"),
+ new LayoutInfo(R.layout.switch_button, "switch_button"),
+ new LayoutInfo(R.layout.textview, "textview"),
+ new LayoutInfo(R.layout.timepicker, "timepicker",
+ new TimePickerModifier()),
+ new LayoutInfo(R.layout.togglebutton_checked, "togglebutton_checked"),
+ new LayoutInfo(R.layout.togglebutton, "togglebutton"),
+ };
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java b/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java
index b30ffd3..9227edd 100644
--- a/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/ThemeDeviceActivity.java
@@ -16,19 +16,17 @@
package android.theme.app;
+import static android.theme.app.TestConfiguration.LAYOUTS;
+import static android.theme.app.TestConfiguration.THEMES;
+
import android.animation.ValueAnimator;
import android.app.Activity;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.os.Build;
import android.os.Bundle;
-import android.theme.app.modifiers.DatePickerModifier;
-import android.theme.app.modifiers.ProgressBarModifier;
-import android.theme.app.modifiers.SearchViewModifier;
-import android.theme.app.modifiers.TimePickerModifier;
-import android.theme.app.modifiers.ViewCheckedModifier;
-import android.theme.app.modifiers.ViewPressedModifier;
+import android.theme.app.modifiers.AbstractLayoutModifier;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,7 +34,6 @@
import android.widget.DatePicker;
import java.io.File;
-import java.lang.Override;
/**
* A activity which display various UI elements with non-modifiable themes.
@@ -53,7 +50,7 @@
*/
private static final long HOLO_CALENDAR_VIEW_ADJUSTMENT_DURATION = 540;
- private Theme mTheme;
+ private ThemeInfo mTheme;
private ReferenceViewGroup mViewGroup;
private File mOutputDir;
private int mLayoutIndex;
@@ -94,9 +91,18 @@
mViewGroup = findViewById(R.id.reference_view_group);
- getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON
- | LayoutParams.FLAG_TURN_SCREEN_ON
- | LayoutParams.FLAG_DISMISS_KEYGUARD );
+ getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // The activity has been created, but we don't want to start image generation until various
+ // asynchronous conditions are satisfied.
+ new ConditionCheck(this, () -> setNextLayout(), message -> finish(message, false))
+ .addCondition("Device is unlocked",
+ () -> !getSystemService(KeyguardManager.class).isDeviceLocked())
+ .addCondition("Window is focused",
+ () -> hasWindowFocus())
+ .addCondition("Activity is resumed",
+ () -> mIsRunning)
+ .start();
}
@Override
@@ -104,8 +110,6 @@
super.onResume();
mIsRunning = true;
-
- setNextLayout();
}
@Override
@@ -115,8 +119,7 @@
if (!isFinishing()) {
// The activity paused for some reason, likely a system crash
// dialog. Finish it so we can move to the next theme.
- Log.w(TAG, "onPause() called without a call to finish()", new RuntimeException());
- finish();
+ Log.e(TAG, "onPause() called without a call to finish(), check system dialogs");
}
super.onPause();
@@ -125,10 +128,7 @@
@Override
protected void onDestroy() {
if (mLayoutIndex < LAYOUTS.length) {
- final Intent data = new Intent();
- data.putExtra(GenerateImagesActivity.EXTRA_REASON, "Only rendered "
- + mLayoutIndex + "/" + LAYOUTS.length + " layouts");
- setResult(RESULT_CANCELED, data);
+ finish("Only rendered " + mLayoutIndex + "/" + LAYOUTS.length + " layouts", false);
}
super.onDestroy();
@@ -139,15 +139,14 @@
*/
private void setNextLayout() {
if (mLayoutIndex >= LAYOUTS.length) {
- setResult(RESULT_OK);
- finish();
+ finish("Rendered all layouts", true);
return;
}
mViewGroup.removeAllViews();
- final Layout layout = LAYOUTS[mLayoutIndex++];
- final LayoutModifier modifier = layout.modifier;
+ final LayoutInfo layout = LAYOUTS[mLayoutIndex++];
+ final AbstractLayoutModifier modifier = layout.modifier;
final String layoutName = String.format("%s_%s", mTheme.name, layout.name);
final LayoutInflater layoutInflater = LayoutInflater.from(mViewGroup.getContext());
final View view = layoutInflater.inflate(layout.id, mViewGroup, false);
@@ -166,9 +165,9 @@
+ " (" + mLayoutIndex + "/" + LAYOUTS.length + ")");
final Runnable generateBitmapRunnable = () ->
- new BitmapTask(view, layoutName, modifier).execute();
+ new BitmapTask(view, layoutName).execute();
- if (view instanceof DatePicker && mTheme.spec == Theme.HOLO) {
+ if (view instanceof DatePicker && mTheme.spec == ThemeInfo.HOLO) {
// The Holo-styled DatePicker uses a CalendarView that has a
// non-configurable adjustment duration of 540ms.
view.postDelayed(generateBitmapRunnable, HOLO_CALENDAR_VIEW_ADJUSTMENT_DURATION);
@@ -177,13 +176,20 @@
}
}
+ private void finish(String reason, boolean success) {
+ final Intent data = new Intent();
+ data.putExtra(GenerateImagesActivity.EXTRA_REASON, reason);
+ setResult(success ? RESULT_OK : RESULT_CANCELED, data);
+
+ if (!isFinishing()) {
+ finish();
+ }
+ }
+
private class BitmapTask extends GenerateBitmapTask {
- private final LayoutModifier mLayoutModifier;
- public BitmapTask(View view, String name, LayoutModifier modifier) {
+ public BitmapTask(View view, String name) {
super(view, mOutputDir, name);
-
- mLayoutModifier = modifier;
}
@Override
@@ -191,250 +197,9 @@
if (success && mIsRunning) {
setNextLayout();
} else {
- Log.e(TAG, "Failed to render view to bitmap: " + mName + " (activity running? "
- + mIsRunning + ")");
- finish();
+ finish("Failed to render view to bitmap: " + mName + " (activity running? "
+ + mIsRunning + ")", false);
}
}
}
-
- /**
- * A class to encapsulate information about a theme.
- */
- static class Theme {
- public static final int HOLO = 0;
- public static final int MATERIAL = 1;
-
- public final int spec;
- public final int id;
- public final int apiLevel;
- public final String name;
-
- private Theme(int spec, int id, int apiLevel, String name) {
- this.spec = spec;
- this.id = id;
- this.apiLevel = apiLevel;
- this.name = name;
- }
- }
-
- // List of themes to verify.
- @SuppressWarnings("deprecation")
- static final Theme[] THEMES = {
- // Holo
- new Theme(Theme.HOLO, android.R.style.Theme_Holo,
- Build.VERSION_CODES.HONEYCOMB, "holo"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog,
- Build.VERSION_CODES.HONEYCOMB, "holo_dialog"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog_MinWidth,
- Build.VERSION_CODES.HONEYCOMB, "holo_dialog_minwidth"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar,
- Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Dialog_NoActionBar_MinWidth,
- Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar_minwidth"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_DialogWhenLarge,
- Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_DialogWhenLarge_NoActionBar,
- Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge_noactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_InputMethod,
- Build.VERSION_CODES.HONEYCOMB, "holo_inputmethod"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar,
- Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar_Fullscreen,
- Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar_fullscreen"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar_Overscan,
- Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_noactionbar_overscan"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_NoActionBar_TranslucentDecor,
- Build.VERSION_CODES.KITKAT, "holo_noactionbar_translucentdecor"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Panel,
- Build.VERSION_CODES.HONEYCOMB, "holo_panel"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Wallpaper,
- Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Wallpaper_NoTitleBar,
- Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper_notitlebar"),
-
- // Holo Light
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light,
- Build.VERSION_CODES.HONEYCOMB, "holo_light"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_DarkActionBar,
- Build.VERSION_CODES.ICE_CREAM_SANDWICH, "holo_light_darkactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog_MinWidth,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_minwidth"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar_minwidth"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_DialogWhenLarge_NoActionBar,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge_noactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar,
- Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen,
- Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar_fullscreen"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_Overscan,
- Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_light_noactionbar_overscan"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor,
- Build.VERSION_CODES.KITKAT, "holo_light_noactionbar_translucentdecor"),
- new Theme(Theme.HOLO, android.R.style.Theme_Holo_Light_Panel,
- Build.VERSION_CODES.HONEYCOMB, "holo_light_panel"),
-
- // Material
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material,
- Build.VERSION_CODES.LOLLIPOP, "material"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog,
- Build.VERSION_CODES.LOLLIPOP, "material_dialog"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_Alert,
- Build.VERSION_CODES.LOLLIPOP, "material_dialog_alert"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_MinWidth,
- Build.VERSION_CODES.LOLLIPOP, "material_dialog_minwidth"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_NoActionBar_MinWidth,
- Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar_minwidth"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Dialog_Presentation,
- Build.VERSION_CODES.LOLLIPOP, "material_dialog_presentation"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge,
- Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_DialogWhenLarge_NoActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge_noactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_InputMethod,
- Build.VERSION_CODES.LOLLIPOP, "material_inputmethod"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_noactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar_Fullscreen,
- Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_fullscreen"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar_Overscan,
- Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_overscan"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_NoActionBar_TranslucentDecor,
- Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_translucentdecor"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Panel,
- Build.VERSION_CODES.LOLLIPOP, "material_panel"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Settings,
- Build.VERSION_CODES.LOLLIPOP, "material_settings"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Voice,
- Build.VERSION_CODES.LOLLIPOP, "material_voice"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Wallpaper,
- Build.VERSION_CODES.LOLLIPOP, "material_wallpaper"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Wallpaper_NoTitleBar,
- Build.VERSION_CODES.LOLLIPOP, "material_wallpaper_notitlebar"),
-
- // Material Light
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light,
- Build.VERSION_CODES.LOLLIPOP, "material_light"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_DarkActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_light_darkactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialog"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Alert,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_alert"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_MinWidth,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_minwidth"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_NoActionBar_MinWidth,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar_minwidth"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Dialog_Presentation,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_presentation"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_DialogWhenLarge_NoActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge_noactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_LightStatusBar,
- Build.VERSION_CODES.M, "material_light_lightstatusbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar,
- Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Fullscreen,
- Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_fullscreen"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_Overscan,
- Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_overscan"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_NoActionBar_TranslucentDecor,
- Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_translucentdecor"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Panel,
- Build.VERSION_CODES.LOLLIPOP, "material_light_panel"),
- new Theme(Theme.MATERIAL, android.R.style.Theme_Material_Light_Voice,
- Build.VERSION_CODES.LOLLIPOP, "material_light_voice")
- };
-
- /**
- * A class to encapsulate information about a layout.
- */
- private static class Layout {
- public final int id;
- public final String name;
- public final LayoutModifier modifier;
-
- private Layout(int id, String name) {
- this(id, name, null);
- }
-
- private Layout(int id, String name, LayoutModifier modifier) {
- this.id = id;
- this.name = name;
- this.modifier = modifier;
- }
- }
-
- // List of layouts to verify for each theme.
- private static final Layout[] LAYOUTS = {
- new Layout(R.layout.button, "button"),
- new Layout(R.layout.button, "button_pressed",
- new ViewPressedModifier()),
- new Layout(R.layout.checkbox, "checkbox"),
- new Layout(R.layout.checkbox, "checkbox_checked",
- new ViewCheckedModifier()),
- new Layout(R.layout.chronometer, "chronometer"),
- new Layout(R.layout.color_blue_bright, "color_blue_bright"),
- new Layout(R.layout.color_blue_dark, "color_blue_dark"),
- new Layout(R.layout.color_blue_light, "color_blue_light"),
- new Layout(R.layout.color_green_dark, "color_green_dark"),
- new Layout(R.layout.color_green_light, "color_green_light"),
- new Layout(R.layout.color_orange_dark, "color_orange_dark"),
- new Layout(R.layout.color_orange_light, "color_orange_light"),
- new Layout(R.layout.color_purple, "color_purple"),
- new Layout(R.layout.color_red_dark, "color_red_dark"),
- new Layout(R.layout.color_red_light, "color_red_light"),
- new Layout(R.layout.datepicker, "datepicker",
- new DatePickerModifier()),
- new Layout(R.layout.edittext, "edittext"),
- new Layout(R.layout.progressbar_horizontal_0, "progressbar_horizontal_0"),
- new Layout(R.layout.progressbar_horizontal_100, "progressbar_horizontal_100"),
- new Layout(R.layout.progressbar_horizontal_50, "progressbar_horizontal_50"),
- new Layout(R.layout.progressbar_large, "progressbar_large",
- new ProgressBarModifier()),
- new Layout(R.layout.progressbar_small, "progressbar_small",
- new ProgressBarModifier()),
- new Layout(R.layout.progressbar, "progressbar",
- new ProgressBarModifier()),
- new Layout(R.layout.radiobutton_checked, "radiobutton_checked"),
- new Layout(R.layout.radiobutton, "radiobutton"),
- new Layout(R.layout.radiogroup_horizontal, "radiogroup_horizontal"),
- new Layout(R.layout.radiogroup_vertical, "radiogroup_vertical"),
- new Layout(R.layout.ratingbar_0, "ratingbar_0"),
- new Layout(R.layout.ratingbar_2point5, "ratingbar_2point5"),
- new Layout(R.layout.ratingbar_5, "ratingbar_5"),
- new Layout(R.layout.ratingbar_0, "ratingbar_0_pressed",
- new ViewPressedModifier()),
- new Layout(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
- new ViewPressedModifier()),
- new Layout(R.layout.ratingbar_5, "ratingbar_5_pressed",
- new ViewPressedModifier()),
- new Layout(R.layout.searchview, "searchview_query",
- new SearchViewModifier(SearchViewModifier.QUERY)),
- new Layout(R.layout.searchview, "searchview_query_hint",
- new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
- new Layout(R.layout.seekbar_0, "seekbar_0"),
- new Layout(R.layout.seekbar_100, "seekbar_100"),
- new Layout(R.layout.seekbar_50, "seekbar_50"),
- new Layout(R.layout.spinner, "spinner"),
- new Layout(R.layout.switch_button_checked, "switch_button_checked"),
- new Layout(R.layout.switch_button, "switch_button"),
- new Layout(R.layout.textview, "textview"),
- new Layout(R.layout.timepicker, "timepicker",
- new TimePickerModifier()),
- new Layout(R.layout.togglebutton_checked, "togglebutton_checked"),
- new Layout(R.layout.togglebutton, "togglebutton"),
- };
}
diff --git a/hostsidetests/theme/app/src/android/theme/app/ThemeInfo.java b/hostsidetests/theme/app/src/android/theme/app/ThemeInfo.java
new file mode 100644
index 0000000..6a3d4aa
--- /dev/null
+++ b/hostsidetests/theme/app/src/android/theme/app/ThemeInfo.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.theme.app;
+
+/**
+ * A class to encapsulate information about a theme.
+ */
+class ThemeInfo {
+ public static final int HOLO = 0;
+ public static final int MATERIAL = 1;
+
+ public final int spec;
+ public final int id;
+ public final int apiLevel;
+ public final String name;
+
+ ThemeInfo(int spec, int id, int apiLevel, String name) {
+ this.spec = spec;
+ this.id = id;
+ this.apiLevel = apiLevel;
+ this.name = name;
+ }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java b/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java
index e9dca7a..2c71cc6 100644
--- a/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java
+++ b/hostsidetests/theme/app/src/android/theme/app/modifiers/AbstractLayoutModifier.java
@@ -16,19 +16,30 @@
package android.theme.app.modifiers;
-import android.theme.app.LayoutModifier;
import android.view.View;
/**
- * {@link LayoutModifier} that does nothing.
+ * {@link AbstractLayoutModifier} that does nothing.
*/
-abstract class AbstractLayoutModifier implements LayoutModifier {
+public abstract class AbstractLayoutModifier {
- @Override
+ /**
+ * Modifies the view before it has been added to a parent. Useful for avoiding animations in
+ * response to setter calls.
+ *
+ * @param view the view inflated by the test activity
+ */
public void modifyViewBeforeAdd(View view) {
+
}
- @Override
+ /**
+ * Modifies the view after it has been added to a parent. Useful for running animations in
+ * response to setter calls.
+ *
+ * @param view the view inflated by the test activity
+ */
public void modifyViewAfterAdd(View view) {
+
}
}
diff --git a/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java b/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java
index f155fcb..58ddb43 100644
--- a/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java
+++ b/hostsidetests/theme/app/src/android/theme/app/modifiers/DatePickerModifier.java
@@ -16,12 +16,11 @@
package android.theme.app.modifiers;
-import android.theme.app.LayoutModifier;
import android.view.View;
import android.widget.DatePicker;
/**
- * {@link LayoutModifier} that sets a precise date on a {@link DatePicker}.
+ * {@link AbstractLayoutModifier} that sets a precise date on a {@link DatePicker}.
*/
public class DatePickerModifier extends AbstractLayoutModifier {
diff --git a/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java b/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java
index dcd8c89..325751f 100644
--- a/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java
+++ b/hostsidetests/theme/app/src/android/theme/app/modifiers/ProgressBarModifier.java
@@ -16,7 +16,6 @@
package android.theme.app.modifiers;
-import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.ProgressBar;
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index 199830f..7a931a4 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -159,7 +159,7 @@
return;
}
- assertTrue("Aborted image generation", generateDeviceImages());
+ assertTrue("Aborted image generation, see device log for details", generateDeviceImages());
// Pull ZIP file from remote device.
final File localZip = File.createTempFile("generated", ".zip");
diff --git a/hostsidetests/usage/AndroidTest.xml b/hostsidetests/usage/AndroidTest.xml
index 9ccc7e1..fc7f46e 100644
--- a/hostsidetests/usage/AndroidTest.xml
+++ b/hostsidetests/usage/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAppUsageTestApp.apk" />
diff --git a/tests/acceleration/Android.mk b/tests/acceleration/Android.mk
index cef4379..8ae5ddc 100644
--- a/tests/acceleration/Android.mk
+++ b/tests/acceleration/Android.mk
@@ -32,7 +32,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
LOCAL_PACKAGE_NAME := CtsAccelerationTestCases
diff --git a/tests/acceleration/AndroidManifest.xml b/tests/acceleration/AndroidManifest.xml
index 1a21554..27ff97a 100644
--- a/tests/acceleration/AndroidManifest.xml
+++ b/tests/acceleration/AndroidManifest.xml
@@ -15,7 +15,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.acceleration.cts">
+ package="android.acceleration.cts"
+ android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
diff --git a/tests/acceleration/AndroidTest.xml b/tests/acceleration/AndroidTest.xml
index b28f845..68eb78f 100644
--- a/tests/acceleration/AndroidTest.xml
+++ b/tests/acceleration/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS Acceleration test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="location" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAccelerationTestCases.apk" />
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 029dc51..8fbc3a2 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -81,7 +81,7 @@
</service>
<service
- android:name=".AccessibilityGestureDetectorTest$StubService"
+ android:name=".GestureDetectionStubAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 27ec20b..b1a4352 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -47,29 +47,23 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
-
-/**
- * Verify that motion events are recognized as accessibility gestures.
- */
+/** Verify that motion events are recognized as accessibility gestures. */
@RunWith(AndroidJUnit4.class)
public class AccessibilityGestureDetectorTest {
// Constants
- static final float GESTURE_LENGTH_INCHES = 1.0f;
- static final long STROKE_MS = 400;
- static final long GESTURE_DISPATCH_TIMEOUT_MS = 3000;
- static final long GESTURE_RECOGNIZE_TIMEOUT_MS = 3000;
- static final long EVENT_DISPATCH_TIMEOUT_MS = 3000;
- static final long EVENT_RECOGNIZE_TIMEOUT_MS = 3000;
+ private static final float GESTURE_LENGTH_INCHES = 1.0f;
+ private static final long STROKE_MS = 400;
+ private static final long GESTURE_DISPATCH_TIMEOUT_MS = 3000;
+ private static final long EVENT_DISPATCH_TIMEOUT_MS = 3000;
- // Member variables
- StubService mService; // Test AccessibilityService that collects gestures.
+ // Test AccessibilityService that collects gestures.
+ GestureDetectionStubAccessibilityService mService;
boolean mHasTouchScreen;
boolean mScreenBigEnough;
- int mStrokeLenPxX; // Gesture stroke size, in pixels
+ int mStrokeLenPxX; // Gesture stroke size, in pixels
int mStrokeLenPxY;
- Point mCenter; // Center of screen. Gestures all start from this point.
+ Point mCenter; // Center of screen. Gestures all start from this point.
PointF mTapLocation;
@Mock AccessibilityService.GestureResultCallback mGestureDispatchCallback;
@@ -94,16 +88,14 @@
windowManager.getDefaultDisplay().getRealMetrics(metrics);
mCenter = new Point((int) metrics.widthPixels / 2, (int) metrics.heightPixels / 2);
mTapLocation = new PointF(mCenter);
- mStrokeLenPxX = (int)(GESTURE_LENGTH_INCHES * metrics.xdpi);
- mStrokeLenPxY = (int)(GESTURE_LENGTH_INCHES * metrics.ydpi);
- mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES)
- && (metrics.heightPixels / (2 * metrics.ydpi) > GESTURE_LENGTH_INCHES);
+ mStrokeLenPxX = (int) (GESTURE_LENGTH_INCHES * metrics.xdpi);
+ mStrokeLenPxY = (int) (GESTURE_LENGTH_INCHES * metrics.ydpi);
+ mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES);
if (!mScreenBigEnough) {
return;
}
-
// Start stub accessibility service.
- mService = StubService.enableSelf(instrumentation);
+ mService = GestureDetectionStubAccessibilityService.enableSelf(instrumentation);
}
@After
@@ -165,7 +157,7 @@
long pathDurationMs = numPathSegments * STROKE_MS;
GestureDescription gesture = new GestureDescription.Builder()
.addStroke(new StrokeDescription(
- linePath(mCenter, delta1, delta2), 0, pathDurationMs, false))
+ linePath(mCenter, delta1, delta2), 0, pathDurationMs, false))
.build();
// Dispatch gesture motions.
@@ -174,9 +166,8 @@
// sendPointerSync() injects events.
mService.clearGestures();
mService.runOnServiceSync(() ->
- mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
- verify(mGestureDispatchCallback,
- timeout(GESTURE_DISPATCH_TIMEOUT_MS).atLeastOnce())
+ mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
+ verify(mGestureDispatchCallback, timeout(GESTURE_DISPATCH_TIMEOUT_MS).atLeastOnce())
.onCompleted(any());
// Wait for gesture recognizer, and check recognized gesture.
@@ -225,15 +216,14 @@
/** Test touch for accessibility events */
private void assertEventAfterGesture(GestureDescription gesture, int... events) {
mService.clearEvents();
- mService.runOnServiceSync(() ->
- mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
- verify(mGestureDispatchCallback,
- timeout(EVENT_DISPATCH_TIMEOUT_MS).atLeastOnce())
+ mService.runOnServiceSync(
+ () -> mService.dispatchGesture(gesture, mGestureDispatchCallback, null));
+ verify(mGestureDispatchCallback, timeout(EVENT_DISPATCH_TIMEOUT_MS).atLeastOnce())
.onCompleted(any());
mService.waitUntilEvent(events.length);
assertEquals(events.length, mService.getEventsSize());
- for (int i = 0 ; i < events.length ; i++) {
+ for (int i = 0; i < events.length; i++) {
assertEquals(events[i], mService.getEvent(i));
}
}
@@ -270,107 +260,4 @@
builder.addStroke(tap2);
return builder.build();
}
-
- /** Acessibility service stub, which will collect recognized gestures. */
- public static class StubService extends InstrumentedAccessibilityService {
- private final Object mLock = new Object();
- private ArrayList<Integer> mCollectedGestures = new ArrayList();
- private ArrayList<Integer> mCollectedEvents = new ArrayList();
-
- public static StubService enableSelf(Instrumentation instrumentation) {
- return InstrumentedAccessibilityService.enableService(
- instrumentation, StubService.class);
- }
-
- @Override
- protected boolean onGesture(int gestureId) {
- synchronized (mCollectedGestures) {
- mCollectedGestures.add(gestureId);
- mCollectedGestures.notifyAll(); // Stop waiting for gesture.
- }
- return true;
- }
-
- public void clearGestures() {
- synchronized (mCollectedGestures) {
- mCollectedGestures.clear();
- }
- }
-
- public int getGesturesSize() {
- synchronized (mCollectedGestures) {
- return mCollectedGestures.size();
- }
- }
-
- public int getGesture(int index) {
- synchronized (mCollectedGestures) {
- return mCollectedGestures.get(index);
- }
- }
-
- /** Wait for onGesture() to collect next gesture. */
- public void waitUntilGesture() {
- synchronized (mCollectedGestures) {
- if (mCollectedGestures.size() > 0) {
- return;
- }
- try {
- mCollectedGestures.wait(GESTURE_RECOGNIZE_TIMEOUT_MS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- @Override
- public void onAccessibilityEvent(AccessibilityEvent event) {
- synchronized (mLock) {
- switch (event.getEventType()) {
- case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
- mCollectedEvents.add(event.getEventType());
- mLock.notifyAll();
- break;
- case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
- case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
- case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
- mCollectedEvents.add(event.getEventType());
- }
- }
- super.onAccessibilityEvent(event);
- }
-
- public void clearEvents() {
- synchronized (mLock) {
- mCollectedEvents.clear();
- }
- }
-
- public int getEventsSize() {
- synchronized (mLock) {
- return mCollectedEvents.size();
- }
- }
-
- public int getEvent(int index) {
- synchronized (mLock) {
- return mCollectedEvents.get(index);
- }
- }
-
- /** Wait for onAccessibilityEvent() to collect next gesture. */
- public void waitUntilEvent(int count) {
- synchronized (mLock) {
- if (mCollectedEvents.size() >= count) {
- return;
- }
- try {
- mLock.wait(EVENT_RECOGNIZE_TIMEOUT_MS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
- }
-
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
new file mode 100644
index 0000000..63601cd
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.app.Instrumentation;
+import android.view.accessibility.AccessibilityEvent;
+import java.util.ArrayList;
+
+/** Accessibility service stub, which will collect recognized gestures. */
+public class GestureDetectionStubAccessibilityService extends InstrumentedAccessibilityService {
+ private static final long GESTURE_RECOGNIZE_TIMEOUT_MS = 3000;
+ private static final long EVENT_RECOGNIZE_TIMEOUT_MS = 3000;
+ // Member variables
+ private final Object mLock = new Object();
+ private ArrayList<Integer> mCollectedGestures = new ArrayList();
+ private ArrayList<Integer> mCollectedEvents = new ArrayList();
+
+ public static GestureDetectionStubAccessibilityService enableSelf(
+ Instrumentation instrumentation) {
+ return InstrumentedAccessibilityService.enableService(
+ instrumentation, GestureDetectionStubAccessibilityService.class);
+ }
+
+ @Override
+ protected boolean onGesture(int gestureId) {
+ synchronized (mCollectedGestures) {
+ mCollectedGestures.add(gestureId);
+ mCollectedGestures.notifyAll(); // Stop waiting for gesture.
+ }
+ return true;
+ }
+
+ public void clearGestures() {
+ synchronized (mCollectedGestures) {
+ mCollectedGestures.clear();
+ }
+ }
+
+ public int getGesturesSize() {
+ synchronized (mCollectedGestures) {
+ return mCollectedGestures.size();
+ }
+ }
+
+ public int getGesture(int index) {
+ synchronized (mCollectedGestures) {
+ return mCollectedGestures.get(index);
+ }
+ }
+
+ /** Wait for onGesture() to collect next gesture. */
+ public void waitUntilGesture() {
+ synchronized (mCollectedGestures) {
+ if (mCollectedGestures.size() > 0) {
+ return;
+ }
+ try {
+ mCollectedGestures.wait(GESTURE_RECOGNIZE_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ synchronized (mLock) {
+ switch (event.getEventType()) {
+ case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
+ mCollectedEvents.add(event.getEventType());
+ mLock.notifyAll();
+ break;
+ case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
+ case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
+ case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
+ mCollectedEvents.add(event.getEventType());
+ }
+ }
+ super.onAccessibilityEvent(event);
+ }
+
+ public void clearEvents() {
+ synchronized (mLock) {
+ mCollectedEvents.clear();
+ }
+ }
+
+ public int getEventsSize() {
+ synchronized (mLock) {
+ return mCollectedEvents.size();
+ }
+ }
+
+ public int getEvent(int index) {
+ synchronized (mLock) {
+ return mCollectedEvents.get(index);
+ }
+ }
+
+ /** Wait for onAccessibilityEvent() to collect next gesture. */
+ public void waitUntilEvent(int count) {
+ synchronized (mLock) {
+ if (mCollectedEvents.size() >= count) {
+ return;
+ }
+ try {
+ mLock.wait(EVENT_RECOGNIZE_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index c0b10fe..f99f8bf 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -22,6 +22,10 @@
<!-- Not testing features backed by native code, so only need to run against one ABI -->
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
+ <option name="user-type" value="system" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 7f66a12..9ef2f3d 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -372,6 +372,16 @@
</intent-filter>
</service>
+ <service android:name="android.app.stubs.TestTileService"
+ android:exported="true"
+ android:label="TestTileService"
+ android:icon="@drawable/robot"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
+ <intent-filter>
+ <action android:name="android.service.quicksettings.action.QS_TILE" />
+ </intent-filter>
+ </service>
+
<activity android:name="android.app.stubs.AutomaticZenRuleActivity">
<intent-filter>
<action android:name="android.app.action.AUTOMATIC_ZEN_RULE" />
diff --git a/tests/app/app/src/android/app/stubs/TestTileService.java b/tests/app/app/src/android/app/stubs/TestTileService.java
new file mode 100644
index 0000000..d3c6db4
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestTileService.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.content.ComponentName;
+import android.os.Debug;
+import android.service.quicksettings.TileService;
+
+public class TestTileService extends TileService {
+
+ public static final String TAG = "TestTileService";
+ public static final String PKG = "android.app.stubs";
+ public static final int ICON_ID = R.drawable.robot;
+
+ private static TestTileService sTestTileService = null;
+ boolean isConnected;
+
+ public static String getId() {
+ return String.format("%s/%s", TestTileService.class.getPackage().getName(),
+ TestTileService.class.getName());
+ }
+
+ public static ComponentName getComponentName() {
+ return new ComponentName(TestTileService.class.getPackage().getName(),
+ TestTileService.class.getName());
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ public static TileService getInstance() {
+ return sTestTileService;
+ }
+
+ public boolean isConnected() {
+ return isConnected;
+ }
+
+ @Override
+ public void onTileAdded() {
+ super.onTileAdded();
+ sTestTileService = this;
+ isConnected = true;
+ }
+
+ @Override
+ public void onTileRemoved() {
+ super.onTileRemoved();
+ isConnected = false;
+ sTestTileService = null;
+ }
+}
diff --git a/tests/app/src/android/app/cts/ConditionTest.java b/tests/app/src/android/app/cts/ConditionTest.java
index b1985d1..1b578f0 100644
--- a/tests/app/src/android/app/cts/ConditionTest.java
+++ b/tests/app/src/android/app/cts/ConditionTest.java
@@ -67,4 +67,47 @@
assertEquals(-1, condition1.icon);
assertEquals(Condition.FLAG_RELEVANT_ALWAYS, condition1.flags);
}
+
+ public void testCopy() {
+ Condition condition = new Condition(mConditionId, mSummary, mState);
+ Condition condition1 = condition.copy();
+ assertEquals(mConditionId, condition1.id);
+ assertEquals(mSummary, condition1.summary);
+ assertEquals("", condition1.line1);
+ assertEquals("", condition1.line2);
+ assertEquals(mState, condition1.state);
+ assertEquals(-1, condition1.icon);
+ assertEquals(Condition.FLAG_RELEVANT_ALWAYS, condition1.flags);
+ }
+
+ public void testIsValidId_null() {
+ assertFalse(Condition.isValidId(null, null));
+ }
+
+ public void testIsValidId_noScheme() {
+ String pkg = this.getClass().getPackage().toString();
+ Uri uri = new Uri.Builder().authority(pkg).build();
+ assertFalse(Condition.isValidId(uri, pkg));
+ }
+
+ public void testIsValidId_wrongAuthority() {
+ String pkg = this.getClass().getPackage().toString();
+ Uri uri = new Uri.Builder().authority(pkg).scheme(Condition.SCHEME).build();
+ assertFalse(Condition.isValidId(uri, "different"));
+ }
+
+ public void testIsValidId() {
+ String pkg = this.getClass().getPackage().toString();
+ Uri uri = new Uri.Builder().authority(pkg).scheme(Condition.SCHEME).build();
+ assertTrue(Condition.isValidId(uri, pkg));
+ }
+
+ public void testNewId() {
+ assertTrue(Condition.isValidId(
+ Condition.newId(mContext).build(), mContext.getPackageName()));
+ }
+
+ public void testRelevanceToString() {
+ assertNotNull(Condition.relevanceToString(Condition.FLAG_RELEVANT_ALWAYS));
+ }
}
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 76cd58c..98533ac 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -470,6 +470,8 @@
receiver.waitForDownloadComplete(SHORT_TIMEOUT, downloadId);
assertSuccessfulDownload(downloadId, downloadLocation);
final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
+ mContext.grantUriPermission("com.android.shell", downloadUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
final ContentResolver contentResolver = mContext.getContentResolver();
assertArrayEquals(hash(contentResolver.openInputStream(downloadUri)),
@@ -502,6 +504,8 @@
"text/plain", downloadFile.getPath(), fileContents.getBytes().length, true);
assertTrue(downloadId >= 0);
final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
+ mContext.grantUriPermission("com.android.shell", downloadUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
assertArrayEquals(hash(new FileInputStream(downloadFile)),
hash(mContext.getContentResolver().openInputStream(mediaStoreUri)));
@@ -555,6 +559,8 @@
assertEquals(testTitle, cursor.getString(0));
}
+ mContext.grantUriPermission("com.android.shell", downloadUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
final String newTitle = "New_title";
updateUri(mediaStoreUri, "_display_name", newTitle);
diff --git a/tests/app/src/android/app/cts/NotificationDecoratedCustomViewStyleTest.java b/tests/app/src/android/app/cts/NotificationDecoratedCustomViewStyleTest.java
new file mode 100644
index 0000000..4a1497f
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationDecoratedCustomViewStyleTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Notification.DecoratedCustomViewStyle;
+import android.app.Notification.DecoratedMediaCustomViewStyle;
+import android.test.AndroidTestCase;
+
+public class NotificationDecoratedCustomViewStyleTest extends AndroidTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testNotificationDecoratedCustomViewStyle_Constructor() {
+ DecoratedCustomViewStyle customViewStyle = new DecoratedCustomViewStyle();
+ assertNotNull(customViewStyle);
+ }
+
+ public void testNotificationDecoratedMediaCustomViewStyle_Constructor() {
+ DecoratedMediaCustomViewStyle customViewStyle = new DecoratedMediaCustomViewStyle();
+ assertNotNull(customViewStyle);
+ }
+}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 543e7e8..9949b56 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -85,6 +85,8 @@
import java.util.Objects;
import java.util.UUID;
+/* This tests NotificationListenerService together with NotificationManager, as you need to have
+ * notifications to manipulate in order to test the listener service. */
public class NotificationManagerTest extends AndroidTestCase {
final String TAG = NotificationManagerTest.class.getSimpleName();
final boolean DEBUG = false;
@@ -1016,6 +1018,189 @@
}
}
+ public void testShowBadging_ranking() throws Exception {
+ if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ return;
+ }
+
+ final int originalBadging = Settings.Secure.getInt(
+ mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING);
+
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_BADGING, 1));
+ assertEquals(1, Settings.Secure.getInt(
+ mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING));
+
+ toggleListenerAccess(TestNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+ try {
+ sendNotification(1, R.drawable.black);
+ Thread.sleep(500); // wait for notification listener to receive notification
+ NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+ NotificationListenerService.Ranking outRanking =
+ new NotificationListenerService.Ranking();
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ rankingMap.getRanking(key, outRanking);
+ assertTrue(outRanking.canShowBadge());
+ }
+ }
+
+ // turn off badging globally
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_BADGING, 0));
+
+ Thread.sleep(500); // wait for ranking update
+
+ rankingMap = mListener.mRankingMap;
+ outRanking = new NotificationListenerService.Ranking();
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ assertFalse(outRanking.canShowBadge());
+ }
+ }
+
+ mListener.resetData();
+ } finally {
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_BADGING, originalBadging));
+ }
+ }
+
+ public void testGetSuppressedVisualEffectsOff_ranking() throws Exception {
+ if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ return;
+ }
+
+ toggleListenerAccess(TestNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ final int notificationId = 1;
+ sendNotification(notificationId, R.drawable.black);
+ Thread.sleep(500); // wait for notification listener to receive notification
+
+ NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+ NotificationListenerService.Ranking outRanking =
+ new NotificationListenerService.Ranking();
+
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ rankingMap.getRanking(key, outRanking);
+
+ // check notification key match
+ assertEquals(0, outRanking.getSuppressedVisualEffects());
+ }
+ }
+ }
+
+ public void testGetSuppressedVisualEffects_ranking() throws Exception {
+ if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ return;
+ }
+
+ final int originalFilter = mNotificationManager.getCurrentInterruptionFilter();
+ try {
+ toggleListenerAccess(TestNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ toggleNotificationPolicyAccess(mContext.getPackageName(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK));
+ } else {
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON));
+ }
+ mNotificationManager.setInterruptionFilter(
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+
+ final int notificationId = 1;
+ // update notification
+ sendNotification(notificationId, R.drawable.black);
+ Thread.sleep(500); // wait for notification listener to receive notification
+
+ NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+ NotificationListenerService.Ranking outRanking =
+ new NotificationListenerService.Ranking();
+
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ rankingMap.getRanking(key, outRanking);
+
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+ assertEquals(SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK,
+ outRanking.getSuppressedVisualEffects());
+ } else {
+ assertEquals(SUPPRESSED_EFFECT_SCREEN_ON,
+ outRanking.getSuppressedVisualEffects());
+ }
+ }
+ }
+ } finally {
+ // reset notification policy
+ mNotificationManager.setInterruptionFilter(originalFilter);
+ }
+
+ }
+
+ public void testKeyChannelGroupOverrideImportanceExplanation_ranking() throws Exception {
+ if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ return;
+ }
+
+ toggleListenerAccess(TestNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ final int notificationId = 1;
+ sendNotification(notificationId, R.drawable.black);
+ Thread.sleep(500); // wait for notification listener to receive notification
+
+ NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+ NotificationListenerService.Ranking outRanking =
+ new NotificationListenerService.Ranking();
+
+ StatusBarNotification sbn = findPostedNotification(notificationId);
+
+ // check that the key and channel ids are the same in the ranking as the posted notification
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ rankingMap.getRanking(key, outRanking);
+
+ // check notification key match
+ assertEquals(sbn.getKey(), outRanking.getKey());
+
+ // check notification channel ids match
+ assertEquals(sbn.getNotification().getChannelId(), outRanking.getChannel().getId());
+
+ // check override group key match
+ assertEquals(sbn.getOverrideGroupKey(), outRanking.getOverrideGroupKey());
+
+ // check importance explanation isn't null
+ assertNotNull(outRanking.getImportanceExplanation());
+ }
+ }
+ }
+
public void testNotify_blockedChannel() throws Exception {
mNotificationManager.cancelAll();
@@ -1714,4 +1899,11 @@
SystemUtil.runWithShellPermissionIdentity(() ->
assertTrue(mNotificationManager.matchesCallFilter(peopleExtras)));
}
+
+ /* Confirm that the optional methods of TestNotificationListener still exist and
+ * don't fail. */
+ public void testNotificationListenerMethods() {
+ NotificationListenerService listener = new TestNotificationListener();
+ listener.onStatusBarIconsBehaviorChanged(false);
+ }
}
diff --git a/tests/app/src/android/app/cts/NotificationStatsTest.java b/tests/app/src/android/app/cts/NotificationStatsTest.java
new file mode 100644
index 0000000..6e3d34c
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationStatsTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.service.notification.NotificationStats;
+import android.test.AndroidTestCase;
+
+
+/** Test the public NotificationStats api. */
+public class NotificationStatsTest extends AndroidTestCase {
+
+ public void testGetDismissalSentiment() {
+ NotificationStats notificationStats = new NotificationStats();
+
+ // Starts at unknown. Cycle through all of the options and back.
+ assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN,
+ notificationStats.getDismissalSentiment());
+ notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEGATIVE);
+ assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE,
+ notificationStats.getDismissalSentiment());
+ notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
+ assertEquals(NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+ notificationStats.getDismissalSentiment());
+ notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_POSITIVE);
+ assertEquals(NotificationStats.DISMISS_SENTIMENT_POSITIVE,
+ notificationStats.getDismissalSentiment());
+ notificationStats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_UNKNOWN);
+ assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN,
+ notificationStats.getDismissalSentiment());
+ }
+
+}
diff --git a/tests/app/src/android/app/cts/TileServiceTest.java b/tests/app/src/android/app/cts/TileServiceTest.java
new file mode 100644
index 0000000..7daab1a
--- /dev/null
+++ b/tests/app/src/android/app/cts/TileServiceTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.UiAutomation;
+import android.app.stubs.TestTileService;
+import android.os.Debug;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.support.test.InstrumentationRegistry;
+import android.test.AndroidTestCase;
+
+import junit.framework.Assert;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TileServiceTest extends AndroidTestCase {
+ final String TAG = TileServiceTest.class.getSimpleName();
+
+ private TileService mTileService;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ toggleServiceAccess(TestTileService.getComponentName().flattenToString(), false);
+ Thread.sleep(200); // wait for service to be unbound
+ assertNull(TestTileService.getInstance());
+ }
+
+ public void testCreateTileService() {
+ final TileService tileService = new TileService();
+ }
+
+ public void testLocked_deviceNotLocked() throws Exception {
+ if (!TileService.isQuickSettingsSupported()) return;
+ startTileService();
+ assertFalse(mTileService.isLocked());
+ }
+
+ public void testSecure_deviceNotSecure() throws Exception {
+ if (!TileService.isQuickSettingsSupported()) return;
+ startTileService();
+ assertFalse(mTileService.isSecure());
+ }
+
+ public void testTile_hasCorrectIcon() throws Exception {
+ if (!TileService.isQuickSettingsSupported()) return;
+ startTileService();
+ Tile tile = mTileService.getQsTile();
+ assertEquals(TestTileService.ICON_ID, tile.getIcon().getResId());
+ }
+
+ public void testShowDialog() throws Exception {
+ if (!TileService.isQuickSettingsSupported()) return;
+ Looper.prepare();
+ Dialog dialog = new AlertDialog.Builder(mContext).create();
+ startTileService();
+ clickTile(TestTileService.getComponentName().flattenToString());
+
+ mTileService.showDialog(dialog);
+
+ assertTrue(dialog.isShowing());
+ dialog.dismiss();
+ }
+
+ public void testUnlockAndRun_phoneIsUnlockedActivityIsRun() throws Exception {
+ if (!TileService.isQuickSettingsSupported()) return;
+ startTileService();
+ assertFalse(mTileService.isLocked());
+
+ TestRunnable testRunnable = new TestRunnable();
+
+ mTileService.unlockAndRun(testRunnable);
+ Thread.sleep(100); // wait for activity to run
+ assertTrue(testRunnable.hasRan);
+ }
+
+ private void startTileService() throws Exception {
+ toggleServiceAccess(TestTileService.getComponentName().flattenToString(), true);
+ Thread.sleep(200); // wait for service to be bound
+ mTileService = TestTileService.getInstance();
+ assertNotNull(mTileService);
+ }
+
+ private void toggleServiceAccess(String componentName, boolean on) throws Exception {
+
+ String command = " cmd statusbar " + (on ? "add-tile " : "remove-tile ")
+ + componentName;
+
+ runCommand(command);
+ }
+
+ private void clickTile(String componentName) throws Exception {
+ runCommand(" cmd statusbar click-tile " + componentName);
+ }
+
+ private void runCommand(String command) throws IOException {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ // Execute command
+ try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
+ Assert.assertNotNull("Failed to execute shell command: " + command, fd);
+ // Wait for the command to finish by reading until EOF
+ try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
+ byte[] buffer = new byte[4096];
+ while (in.read(buffer) > 0) {}
+ } catch (IOException e) {
+ throw new IOException("Could not read stdout of command: " + command, e);
+ }
+ } finally {
+ uiAutomation.destroy();
+ }
+ }
+
+ class TestRunnable implements Runnable {
+ boolean hasRan = false;
+
+ @Override
+ public void run() {
+ hasRan = true;
+ }
+ }
+}
diff --git a/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index cc1d479..1bd90a5 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -243,6 +243,63 @@
assertDesiredDimension(new Point(w, min.y / 2), new Point(w, min.y / 2));
}
+ @Test
+ public void wallpaperColors_primary() {
+ Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(tmpWallpaper);
+ canvas.drawColor(Color.RED);
+
+ try {
+ mWallpaperManager.setBitmap(tmpWallpaper);
+ WallpaperColors colors = mWallpaperManager.getWallpaperColors(
+ WallpaperManager.FLAG_SYSTEM);
+
+ // Check that primary color is almost red
+ Color primary = colors.getPrimaryColor();
+ final float delta = 0.1f;
+ Assert.assertEquals("red", 1f, primary.red(), delta);
+ Assert.assertEquals("green", 0f, primary.green(), delta);
+ Assert.assertEquals("blue", 0f, primary.blue(), delta);
+
+ Assert.assertNull(colors.getSecondaryColor());
+ Assert.assertNull(colors.getTertiaryColor());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ tmpWallpaper.recycle();
+ }
+ }
+
+
+ @Test
+ public void wallpaperColors_secondary() {
+ Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(tmpWallpaper);
+ canvas.drawColor(Color.RED);
+ // Make 20% of the wallpaper BLUE so that secondary color is BLUE
+ canvas.clipRect(0, 0, 100, 20);
+ canvas.drawColor(Color.BLUE);
+
+ try {
+ mWallpaperManager.setBitmap(tmpWallpaper);
+ WallpaperColors colors = mWallpaperManager.getWallpaperColors(
+ WallpaperManager.FLAG_SYSTEM);
+
+ // Check that the secondary color is almost blue
+ Color secondary = colors.getSecondaryColor();
+ final float delta = 0.1f;
+ Assert.assertEquals("red", 0f, secondary.red(), delta);
+ Assert.assertEquals("green", 0f, secondary.green(), delta);
+ Assert.assertEquals("blue", 1f, secondary.blue(), delta);
+
+ Assert.assertNull(colors.getTertiaryColor());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ tmpWallpaper.recycle();
+ }
+ }
+
private void assertDesiredDimension(Point suggestedSize, Point expectedSize) {
mWallpaperManager.suggestDesiredDimensions(suggestedSize.x, suggestedSize.y);
Point actualSize = new Point(mWallpaperManager.getDesiredMinimumWidth(),
diff --git a/tests/app/src/android/app/cts/WearableExtenderTest.java b/tests/app/src/android/app/cts/WearableExtenderTest.java
new file mode 100644
index 0000000..eb3e5d8
--- /dev/null
+++ b/tests/app/src/android/app/cts/WearableExtenderTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import android.app.Notification;
+import android.app.Notification.Action;
+import android.app.Notification.WearableExtender;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.view.Gravity;
+import java.util.ArrayList;
+import java.util.List;
+
+public class WearableExtenderTest extends AndroidTestCase {
+
+ private Context mContext;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getContext();
+ }
+
+ public void testWearableExtender() {
+ final String bridgeTag = "bridge_tag";
+ final String dismissalId = "dismissal_id";
+ final int contentActionIndex = 2;
+ final Bitmap background = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
+ PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Notification page1 = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("page1")
+ .build();
+ Notification page2 = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("page2")
+ .build();
+ List<Notification> pages = new ArrayList<>();
+ pages.add(page2);
+ final int gravity = Gravity.LEFT;
+ final int icon = 3;
+ final int height = 4;
+ final int size = 5;
+ final int timeout = 6;
+
+ WearableExtender extender = new WearableExtender()
+ .setStartScrollBottom(true)
+ .setContentIntentAvailableOffline(true)
+ .setHintContentIntentLaunchesActivity(true)
+ .setBridgeTag(bridgeTag)
+ .setDismissalId(dismissalId)
+ .setContentAction(contentActionIndex)
+ // deprecated methods follow
+ .setBackground(background)
+ .setGravity(gravity)
+ .setContentIcon(icon)
+ .setContentIconGravity(gravity)
+ .setCustomContentHeight(height)
+ .setCustomSizePreset(size)
+ .setDisplayIntent(pendingIntent)
+ .setHintAmbientBigPicture(true)
+ .setHintAvoidBackgroundClipping(true)
+ .setHintHideIcon(true)
+ .setHintScreenTimeout(timeout)
+ .setHintShowBackgroundOnly(true)
+ .addPage(page1)
+ .clearPages()
+ .addPages(pages);
+
+ assertTrue(extender.getStartScrollBottom());
+ assertTrue(extender.getContentIntentAvailableOffline());
+ assertTrue(extender.getHintContentIntentLaunchesActivity());
+ assertEquals(bridgeTag, extender.getBridgeTag());
+ assertEquals(dismissalId, extender.getDismissalId());
+ assertEquals(contentActionIndex, extender.getContentAction());
+ // deprecated methods follow
+ assertEquals(background, extender.getBackground());
+ assertEquals(gravity, extender.getGravity());
+ assertEquals(icon, extender.getContentIcon());
+ assertEquals(gravity, extender.getContentIconGravity());
+ assertEquals(height, extender.getCustomContentHeight());
+ assertEquals(size, extender.getCustomSizePreset());
+ assertEquals(pendingIntent, extender.getDisplayIntent());
+ assertTrue(extender.getHintAmbientBigPicture());
+ assertTrue(extender.getHintAvoidBackgroundClipping());
+ assertTrue(extender.getHintHideIcon());
+ assertEquals(timeout, extender.getHintScreenTimeout());
+ assertTrue(extender.getHintShowBackgroundOnly());
+ assertEquals(1, extender.getPages().size());
+ assertEquals(page2, extender.getPages().get(0));
+ }
+
+ public void testWearableExtenderActions() {
+ Notification.Action a = newActionBuilder().build();
+ Notification.Action b = newActionBuilder().build();
+ Notification.Action c = newActionBuilder().build();
+ List<Action> actions = new ArrayList<>();
+ actions.add(b);
+ actions.add(c);
+
+ WearableExtender extender = new WearableExtender()
+ .addAction(a)
+ .addActions(actions)
+ .setContentAction(1);
+
+ assertEquals(3, extender.getActions().size());
+ assertEquals(b, extender.getActions().get(extender.getContentAction()));
+ }
+
+ public void testWearableExtender_clearActions() {
+ WearableExtender extender = new WearableExtender()
+ .addAction(newActionBuilder().build());
+
+ extender.clearActions();
+
+ assertEquals(0, extender.getActions().size());
+ }
+
+ public void testWearableExtender_clone() {
+ final String bridgeTag = "bridge_tag";
+ final String dismissalId = "dismissal_id";
+ final int contentActionIndex = 2;
+ WearableExtender original = new WearableExtender()
+ .addAction(newActionBuilder().build())
+ .setStartScrollBottom(true)
+ .setContentIntentAvailableOffline(true)
+ .setHintContentIntentLaunchesActivity(true)
+ .setBridgeTag(bridgeTag)
+ .setDismissalId(dismissalId)
+ .setContentAction(contentActionIndex);
+
+ // WHEN the enter is cloned
+ WearableExtender clone = original.clone();
+ // and WHEN the original is modified
+ original.clearActions();
+
+ assertTrue(clone.getStartScrollBottom());
+ assertTrue(clone.getContentIntentAvailableOffline());
+ assertTrue(clone.getHintContentIntentLaunchesActivity());
+ assertEquals(bridgeTag, clone.getBridgeTag());
+ assertEquals(dismissalId, clone.getDismissalId());
+ assertEquals(contentActionIndex, clone.getContentAction());
+ assertEquals(1, clone.getActions().size());
+ }
+
+ public void testWearableExtender_extend() {
+ final String title = "test_title";
+ final String bridgeTag = "bridge_tag";
+ final String dismissalId = "dismissal_id";
+ final int contentActionIndex = 2;
+ Notification.Builder notifBuilder = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle(title);
+ WearableExtender extender = new WearableExtender()
+ .addAction(newActionBuilder().build())
+ .setStartScrollBottom(true)
+ .setContentIntentAvailableOffline(true)
+ .setHintContentIntentLaunchesActivity(true)
+ .setBridgeTag(bridgeTag)
+ .setDismissalId(dismissalId)
+ .setContentAction(contentActionIndex);
+
+ extender.extend(notifBuilder);
+
+ WearableExtender result = new WearableExtender(notifBuilder.build());
+ assertTrue(result.getStartScrollBottom());
+ assertTrue(result.getContentIntentAvailableOffline());
+ assertTrue(result.getHintContentIntentLaunchesActivity());
+ assertEquals(bridgeTag, result.getBridgeTag());
+ assertEquals(dismissalId, result.getDismissalId());
+ assertEquals(contentActionIndex, result.getContentAction());
+ assertEquals(1, result.getActions().size());
+ }
+
+ public void testWriteToParcel() {
+ final String bridgeTag = "bridge_tag";
+ final String dismissalId = "dismissal_id";
+ final int contentActionIndex = 2;
+ Notification.Action action = newActionBuilder().build();
+ final Bitmap background = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
+ PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Notification page1 = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("page1")
+ .build();
+ Notification page2 = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("page2")
+ .build();
+ List<Notification> pages = new ArrayList<>();
+ pages.add(page2);
+ final int gravity = Gravity.LEFT;
+ final int icon = 3;
+ final int height = 4;
+ final int size = 5;
+ final int timeout = 6;
+
+ Notification notif = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("test_title")
+ .extend(new Notification.WearableExtender()
+ .setStartScrollBottom(true)
+ .setContentIntentAvailableOffline(true)
+ .setHintContentIntentLaunchesActivity(true)
+ .setBridgeTag(bridgeTag)
+ .setDismissalId(dismissalId)
+ .addAction(action)
+ .setContentAction(contentActionIndex)
+ // deprecated methods follow
+ .setBackground(background)
+ .setGravity(gravity)
+ .setContentIcon(icon)
+ .setContentIconGravity(gravity)
+ .setCustomContentHeight(height)
+ .setCustomSizePreset(size)
+ .setDisplayIntent(pendingIntent)
+ .setHintAmbientBigPicture(true)
+ .setHintAvoidBackgroundClipping(true)
+ .setHintHideIcon(true)
+ .setHintScreenTimeout(timeout)
+ .setHintShowBackgroundOnly(true)
+ .addPage(page1))
+ .build();
+
+ Parcel parcel = Parcel.obtain();
+ notif.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Notification result = new Notification(parcel);
+
+ WearableExtender extender = new WearableExtender(result);
+ assertTrue(extender.getStartScrollBottom());
+ assertTrue(extender.getContentIntentAvailableOffline());
+ assertTrue(extender.getHintContentIntentLaunchesActivity());
+ assertEquals(bridgeTag, extender.getBridgeTag());
+ assertEquals(dismissalId, extender.getDismissalId());
+ assertEquals(contentActionIndex, extender.getContentAction());
+ assertEquals(1, extender.getActions().size());
+ // deprecated methods follow
+ assertNotNull(extender.getBackground());
+ assertEquals(gravity, extender.getGravity());
+ assertEquals(icon, extender.getContentIcon());
+ assertEquals(gravity, extender.getContentIconGravity());
+ assertEquals(height, extender.getCustomContentHeight());
+ assertEquals(size, extender.getCustomSizePreset());
+ assertEquals(pendingIntent, extender.getDisplayIntent());
+ assertTrue(extender.getHintAmbientBigPicture());
+ assertTrue(extender.getHintAvoidBackgroundClipping());
+ assertTrue(extender.getHintHideIcon());
+ assertEquals(timeout, extender.getHintScreenTimeout());
+ assertTrue(extender.getHintShowBackgroundOnly());
+ assertEquals(1, extender.getPages().size());
+ }
+
+ private static Notification.Action.Builder newActionBuilder() {
+ return new Notification.Action.Builder(0, "title", null);
+ }
+}
\ No newline at end of file
diff --git a/tests/autofillservice/Android.mk b/tests/autofillservice/Android.mk
index 5d74e87..3b8ff6c 100644
--- a/tests/autofillservice/Android.mk
+++ b/tests/autofillservice/Android.mk
@@ -29,6 +29,7 @@
ctstestrunner \
truth-prebuilt \
ub-uiautomator \
+ CtsMockInputMethodLib \
testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 5955274..eee73f5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -27,7 +27,8 @@
<uses-library android:name="android.test.runner" />
- <activity android:name=".LoginActivity" >
+ <activity android:name=".LoginActivity"
+ android:screenOrientation="portrait">
<intent-filter>
<!-- This intent filter is not really needed by CTS, but it makes easier to launch
this app during CTS development... -->
diff --git a/tests/autofillservice/AndroidTest.xml b/tests/autofillservice/AndroidTest.xml
index e7413b1..d59e349 100644
--- a/tests/autofillservice/AndroidTest.xml
+++ b/tests/autofillservice/AndroidTest.xml
@@ -24,6 +24,16 @@
<option name="test-file-name" value="CtsAutoFillServiceTestCases.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <!--
+ MockIME always needs to be installed as a full package, even when CTS is running
+ for instant apps.
+ -->
+ <option name="force-install-mode" value="FULL"/>
+ <option name="test-file-name" value="CtsMockInputMethod.apk" />
+ </target_preparer>
+
<!-- TODO: preparer below should be enabled only when running as cts-instant -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="cmd autofill set bind-instant-service-allowed true" />
@@ -36,4 +46,10 @@
<option name="shell-timeout" value="12000000"/>
</test>
+ <!-- Collect the files generated on error -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/CtsAutoFillServiceTestCases" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="false" />
+ </metrics_collector>
</configuration>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
index cb98b54..92821a3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
@@ -53,7 +53,7 @@
}
@Test
- @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
datasetAuthTwoFields(true);
}
@@ -136,7 +136,7 @@
}
@Test
- @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
public void testDatasetAuthTwoFieldsReplaceResponse() throws Exception {
// Set service.
enableService();
@@ -198,7 +198,7 @@
}
@Test
- @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
public void testDatasetAuthTwoFieldsNoValues() throws Exception {
// Set service.
enableService();
@@ -242,7 +242,7 @@
}
@Test
- @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
public void testDatasetAuthTwoDatasets() throws Exception {
// Set service.
enableService();
@@ -297,13 +297,13 @@
}
@Test
- @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
public void testDatasetAuthMixedSelectAuth() throws Exception {
datasetAuthMixedTest(true);
}
@Test
- @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
public void testDatasetAuthMixedSelectNonAuth() throws Exception {
datasetAuthMixedTest(false);
}
@@ -363,7 +363,7 @@
}
@Test
- @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
public void testDatasetAuthNoFiltering() throws Exception {
// Set service.
enableService();
@@ -421,7 +421,7 @@
}
@Test
- @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
public void testDatasetAuthFilteringUsingAutofillValue() throws Exception {
// Set service.
enableService();
@@ -577,13 +577,13 @@
}
@Test
- @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
public void testDatasetAuthMixedFilteringSelectAuth() throws Exception {
datasetAuthMixedFilteringTest(true);
}
@Test
- @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDatasetAuthFilteringUsingRegex() is enough")
public void testDatasetAuthMixedFilteringSelectNonAuth() throws Exception {
datasetAuthMixedFilteringTest(false);
}
@@ -668,13 +668,13 @@
}
@Test
- @AppModeFull // testDatasetAuthClientStateSetOnIntentOnly() is enough to test ephemeral apps
+ @AppModeFull(reason = "testDatasetAuthClientStateSetOnIntentOnly() is enough")
public void testDatasetAuthClientStateSetOnFillResponseOnly() throws Exception {
fillDatasetAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
}
@Test
- @AppModeFull // testDatasetAuthClientStateSetOnIntentOnly() is enough to test ephemeral apps
+ @AppModeFull(reason = "testDatasetAuthClientStateSetOnIntentOnly() is enough")
public void testDatasetAuthClientStateSetOnIntentAndFillResponse() throws Exception {
fillDatasetAuthWithClientState(ClientStateLocation.BOTH);
}
@@ -743,7 +743,7 @@
}
@Test
- @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
public void testFillResponseAuthBothFieldsUserCancelsFirstAttempt() throws Exception {
fillResponseAuthBothFields(true);
}
@@ -837,7 +837,7 @@
}
@Test
- @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
public void testFillResponseAuthJustOneField() throws Exception {
// Set service.
enableService();
@@ -902,7 +902,7 @@
}
@Test
- @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
public void testFillResponseAuthWhenAppCallsCancel() throws Exception {
// Set service.
enableService();
@@ -955,13 +955,13 @@
}
@Test
- @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
public void testFillResponseAuthServiceHasNoDataButCanSave() throws Exception {
fillResponseAuthServiceHasNoDataTest(true);
}
@Test
- @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFillResponseAuthBothFields() is enough")
public void testFillResponseAuthServiceHasNoData() throws Exception {
fillResponseAuthServiceHasNoDataTest(false);
}
@@ -1034,13 +1034,13 @@
}
@Test
- @AppModeFull // testFillResponseAuthClientStateSetOnIntentOnly() is enough to test ephemeral
+ @AppModeFull(reason = "testFillResponseAuthClientStateSetOnIntentOnly() is enough")
public void testFillResponseAuthClientStateSetOnFillResponseOnly() throws Exception {
fillResponseAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
}
@Test
- @AppModeFull // testFillResponseAuthClientStateSetOnIntentOnly() is enough to test ephemeral
+ @AppModeFull(reason = "testFillResponseAuthClientStateSetOnIntentOnly() is enough")
public void testFillResponseAuthClientStateSetOnIntentAndFillResponse() throws Exception {
fillResponseAuthWithClientState(ClientStateLocation.BOTH);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
index 3a0c294..cabdee3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
@@ -51,7 +51,7 @@
* redundant tests and add more tests (like triggering autofill using different views) to
* CheckoutActivityTest.
*/
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class AutofillValueTest
extends AutoFillServiceTestCase.AutoActivityLaunch<AllAutofillableViewsActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java b/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java
index 805db4e..73817f6 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/BatchUpdatesTest.java
@@ -32,7 +32,7 @@
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class BatchUpdatesTest {
private final BatchUpdates.Builder mBuilder = new BatchUpdates.Builder();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
index 004928a..646aa61 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CharSequenceTransformationTest.java
@@ -38,7 +38,7 @@
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class CharSequenceTransformationTest {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index ac181ec..dead535 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -115,7 +115,7 @@
}
@Test
- @AppModeFull // testAutofill() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofill() is enough")
public void testAutofillDynamicAdapter() throws Exception {
// Set activity.
mActivity.onCcExpiration((v) -> v.setAdapter(new ArrayAdapter<String>(getContext(),
@@ -158,7 +158,7 @@
// TODO: this should be a pure unit test exercising onProvideAutofillStructure(),
// but that would require creating a custom ViewStructure.
@Test
- @AppModeFull // Unit test
+ @AppModeFull(reason = "Unit test")
public void testGetAutofillOptionsSorted() throws Exception {
// Set service.
enableService();
@@ -248,13 +248,13 @@
}
@Test
- @AppModeFull // Service-specific test
+ @AppModeFull(reason = "Service-specific test")
public void testCustomizedSaveUi() throws Exception {
customizedSaveUi(false);
}
@Test
- @AppModeFull // Service-specific test
+ @AppModeFull(reason = "Service-specific test")
public void testCustomizedSaveUiWithContentDescription() throws Exception {
customizedSaveUi(true);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java b/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java
index bb429d4..a00e0d3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CompositeUserDataTest.java
@@ -33,7 +33,7 @@
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class CompositeUserDataTest {
private final String mShortValue = Strings.repeat("k", UserData.getMinValueLength() - 1);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java
index 49e772d..13896aa 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionDateTest.java
@@ -37,7 +37,7 @@
import java.util.Calendar;
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class CustomDescriptionDateTest
extends AutoFillServiceTestCase.AutoActivityLaunch<DatePickerSpinnerActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
index 2f48835..2abde4f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionTest.java
@@ -46,7 +46,7 @@
import java.util.function.BiFunction;
import java.util.regex.Pattern;
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class CustomDescriptionTest extends AbstractLoginActivityTestCase {
/**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java
index 39f3a58..5b3f62d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CustomDescriptionUnitTest.java
@@ -38,7 +38,7 @@
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class CustomDescriptionUnitTest {
private final CustomDescription.Builder mBuilder =
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
index 85e07ba..9a2138a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
@@ -17,14 +17,27 @@
package android.autofillservice.cts;
import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
import static com.android.compatibility.common.util.ShellUtils.sendKeyEvent;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
import android.autofillservice.cts.CannedFillResponse.CannedDataset;
import android.content.IntentSender;
+import android.os.Process;
import android.platform.test.annotations.AppModeFull;
+import android.support.test.InstrumentationRegistry;
+import android.view.View;
import android.widget.EditText;
+import com.android.cts.mockime.ImeCommand;
+import com.android.cts.mockime.ImeEventStream;
+import com.android.cts.mockime.ImeSettings;
+import com.android.cts.mockime.MockImeSession;
+
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -103,7 +116,7 @@
}
@Test
- public void testFilter_usingKeyboard() throws Exception {
+ public void testFilter_injectingEvents() throws Exception {
final String aa = "Two A's";
final String ab = "A and B";
final String b = "Only B";
@@ -159,7 +172,78 @@
}
@Test
- @AppModeFull // testFilter() is enough to test ephemeral apps support
+ public void testFilter_usingKeyboard() throws Exception {
+ final String aa = "Two A's";
+ final String ab = "A and B";
+ final String b = "Only B";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "aa")
+ .setPresentation(createPresentation(aa))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "ab")
+ .setPresentation(createPresentation(ab))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "b")
+ .setPresentation(createPresentation(b))
+ .build())
+ .build());
+
+ final String marker = mActivity.getMarker();
+
+ try (MockImeSession mockImeSession = MockImeSession.create(
+ mContext, InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = mockImeSession.openEventStream();
+
+ // Trigger auto-fill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Wait until the MockIme gets bound to the TestActivity.
+ expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+ expectEvent(stream, editorMatcher("onStartInput", marker), MOCK_IME_TIMEOUT_MS);
+
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // Only two datasets start with 'a'
+ final ImeCommand cmd1 = mockImeSession.callCommitText("a", 1);
+ expectCommand(stream, cmd1, MOCK_IME_TIMEOUT_MS);
+
+ mUiBot.assertDatasets(aa, ab);
+
+ // Only one dataset start with 'aa'
+ final ImeCommand cmd2 = mockImeSession.callCommitText("a", 1);
+ expectCommand(stream, cmd2, MOCK_IME_TIMEOUT_MS);
+
+ mUiBot.assertDatasets(aa);
+
+ // Only two datasets start with 'a'
+ sendKeyEvent("KEYCODE_DEL"); // TODO: add new method on MockIme for it
+ mUiBot.assertDatasets(aa, ab);
+ // With no filter text all datasets should be shown
+ sendKeyEvent("KEYCODE_DEL"); // TODO: add new method on MockIme for it
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // No dataset start with 'aaa'
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ final ImeCommand cmd3 = mockImeSession.callCommitText("aaa", 1);
+ expectCommand(stream, cmd3, MOCK_IME_TIMEOUT_MS);
+ callback.assertUiHiddenEvent(mActivity.getUsername());
+ mUiBot.assertNoDatasets();
+ }
+ }
+
+ @Test
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_nullValuesAlwaysMatched() throws Exception {
final String aa = "Two A's";
final String ab = "A and B";
@@ -212,7 +296,7 @@
}
@Test
- @AppModeFull // testFilter() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_differentPrefixes() throws Exception {
final String a = "aaa";
final String b = "bra";
@@ -254,7 +338,7 @@
}
@Test
- @AppModeFull // testFilter() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_usingRegex() throws Exception {
// Dataset presentations.
final String aa = "Two A's";
@@ -310,7 +394,7 @@
}
@Test
- @AppModeFull // testFilter() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_disabledUsingNullRegex() throws Exception {
// Dataset presentations.
final String unfilterable = "Unfilterabled";
@@ -373,7 +457,7 @@
}
@Test
- @AppModeFull // testFilter() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_mixPlainAndRegex() throws Exception {
final String plain = "Plain";
final String regexPlain = "RegexPlain";
@@ -425,7 +509,7 @@
}
@Test
- @AppModeFull // testFilter_usingKeyboard() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testFilter_usingKeyboard() is enough")
public void testFilter_mixPlainAndRegex_usingKeyboard() throws Exception {
final String plain = "Plain";
final String regexPlain = "RegexPlain";
@@ -477,16 +561,19 @@
}
@Test
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_resetFilter_chooseFirst() throws Exception {
resetFilterTest(1);
}
@Test
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_resetFilter_chooseSecond() throws Exception {
resetFilterTest(2);
}
@Test
+ @AppModeFull(reason = "testFilter() is enough")
public void testFilter_resetFilter_chooseThird() throws Exception {
resetFilterTest(3);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
index 2554a5b..5202f52 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
@@ -34,7 +34,7 @@
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class DatasetTest {
private final AutofillId mId = new AutofillId(42);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
index 35f3b73..decc4b7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AppModeFull;
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class DatePickerCalendarActivityTest extends DatePickerTestCase<DatePickerCalendarActivity> {
@Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
index 291d5aa..4b63e10 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AppModeFull;
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class DatePickerSpinnerActivityTest extends DatePickerTestCase<DatePickerSpinnerActivity> {
@Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java
index 8f2d0ee..c6385ed 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DateTransformationTest.java
@@ -39,7 +39,7 @@
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class DateTransformationTest {
@Mock private ValueFinder mValueFinder;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java b/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java
index 6f59302..f30aaf0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DateValueSanitizerTest.java
@@ -34,7 +34,7 @@
import java.util.Date;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class DateValueSanitizerTest {
private static final String TAG = "DateValueSanitizerTest";
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java b/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
index 77f5efd..49a43fe 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
@@ -207,7 +207,7 @@
}
@Test
- @AppModeFull // testDisableApp() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDisableApp() is enough")
public void testDisableAppThenWaitToReenableIt() throws Exception {
// Set service.
enableService();
@@ -233,7 +233,7 @@
}
@Test
- @AppModeFull // testDisableApp() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDisableApp() is enough")
public void testDisableAppThenResetServiceToReenableIt() throws Exception {
enableService();
sReplier.addResponse(new CannedFillResponse.Builder()
@@ -277,7 +277,7 @@
}
@Test
- @AppModeFull // testDisableActivity() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDisableActivity() is enough")
public void testDisableActivityThenWaitToReenableIt() throws Exception {
// Set service.
enableService();
@@ -306,7 +306,7 @@
}
@Test
- @AppModeFull // testDisableActivity() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testDisableActivity() is enough")
public void testDisableActivityThenResetServiceToReenableIt() throws Exception {
enableService();
sReplier.addResponse(new CannedFillResponse.Builder()
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
index 5f81df2..20a184f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
@@ -44,7 +44,7 @@
import java.util.List;
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class FieldsClassificationTest extends AbstractGridActivityTestCase {
@ClassRule
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java b/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java
index 2e1ae0d..2c6bfe5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FillEventHistoryTest.java
@@ -63,7 +63,7 @@
/**
* Test that uses {@link LoginActivity} to test {@link FillEventHistory}.
*/
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class FillEventHistoryTest extends AbstractLoginActivityTestCase {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java b/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
index f0b7bad..adae5f7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
@@ -40,7 +40,7 @@
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class FillResponseTest {
private final AutofillId mAutofillId = new AutofillId(42);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java b/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
index f0f5470..317c3fa 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ImageTransformationTest.java
@@ -37,7 +37,7 @@
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class ImageTransformationTest {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
index 974f0cc..43000cc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
@@ -35,7 +35,7 @@
/**
* Test case for an activity containing non-TextField views with initial values set on XML.
*/
-@AppModeFull // CheckoutActivityTest() is enough to test ephemeral apps support
+@AppModeFull(reason = "CheckoutActivityTest() is enough")
public class InitializedCheckoutActivityTest
extends AutoFillServiceTestCase.AutoActivityLaunch<InitializedCheckoutActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index 939792c..4cebbb2 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -55,6 +56,8 @@
public static final String BACKDOOR_USERNAME = "LemmeIn";
public static final String BACKDOOR_PASSWORD_SUBSTRING = "pass";
+ private static final String TEST_MARKER_PREFIX = "android.autofillservice.cts.LoginActivity";
+
private LinearLayout mUsernameContainer;
private TextView mUsernameLabel;
private EditText mUsernameEditText;
@@ -71,6 +74,9 @@
private CountDownLatch mLoginLatch;
private String mLoginMessage;
+ private final String mTestMarker = TEST_MARKER_PREFIX + "/"
+ + SystemClock.elapsedRealtimeNanos();
+
/**
* Gets the expected welcome message for a given username.
*/
@@ -78,6 +84,13 @@
return String.format(WELCOME_TEMPLATE, username);
}
+ /**
+ * Gets the marker used on MockIME-based tests.
+ */
+ String getMarker() {
+ return mTestMarker;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -90,6 +103,8 @@
mCancelButton = findViewById(R.id.cancel);
mUsernameLabel = findViewById(R.id.username_label);
mUsernameEditText = findViewById(R.id.username);
+ Log.d(TAG, "marker: " + mTestMarker);
+ mUsernameEditText.setPrivateImeOptions(mTestMarker);
mPasswordLabel = findViewById(R.id.password_label);
mPasswordEditText = findViewById(R.id.password);
mOutput = findViewById(R.id.output);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index e39cdf9..d5325f7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -134,13 +134,13 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutofillManuallyAfterServiceReturnedNoDatasets() throws Exception {
autofillAfterServiceReturnedNoDatasets(true);
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutofillAutomaticallyAfterServiceReturnedNoDatasets() throws Exception {
autofillAfterServiceReturnedNoDatasets(false);
}
@@ -187,13 +187,13 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutofillManuallyAndSaveAfterServiceReturnedNoDatasets() throws Exception {
autofillAndSaveAfterServiceReturnedNoDatasets(true);
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutofillAutomaticallyAndSaveAfterServiceReturnedNoDatasets() throws Exception {
autofillAndSaveAfterServiceReturnedNoDatasets(false);
}
@@ -227,7 +227,7 @@
* workflow was requested.
*/
@Test
- @AppModeFull // testAutoFillNoDatasets() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillNoDatasets() is enough")
public void testMultipleIterationsAfterServiceReturnedNoDatasets() throws Exception {
// Set service.
enableService();
@@ -270,7 +270,7 @@
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyAlwaysCallServiceAgain() throws Exception {
// Set service.
enableService();
@@ -304,13 +304,13 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset_withHeaderAndFooter() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset_withHeaderAndFooter() is enough")
public void testAutoFillOneDataset_withHeader() throws Exception {
autofillOneDatasetTest(BorderType.HEADER_ONLY);
}
@Test
- @AppModeFull // testAutoFillOneDataset_withHeaderAndFooter() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset_withHeaderAndFooter() is enough")
public void testAutoFillOneDataset_withFooter() throws Exception {
autofillOneDatasetTest(BorderType.FOOTER_ONLY);
}
@@ -382,6 +382,7 @@
@Test
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutofillAgainAfterOnFailure() throws Exception {
// Set service.
enableService();
@@ -416,9 +417,10 @@
@Test
public void testDatasetPickerPosition() throws Exception {
- // TODO: currently disabled because the screenshot contains elements external to the
- // activity that can change (for exmaple, clock), which causes flakiness to the test.
+ // TODO(b/75281985): currently disabled because the screenshot contains elements external to
+ // the activity that can change (for exmaple, clock), which causes flakiness to the test.
final boolean compareBitmaps = false;
+
final boolean pickerAndViewBoundsMatches = !isAutofillWindowFullScreen(mContext);
// Set service.
@@ -500,7 +502,7 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillTwoDatasetsSameNumberOfFields() throws Exception {
// Set service.
enableService();
@@ -539,13 +541,13 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsAll() throws Exception {
autoFillTwoDatasetsUnevenNumberOfFieldsTest(true);
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsOne() throws Exception {
autoFillTwoDatasetsUnevenNumberOfFieldsTest(false);
}
@@ -597,7 +599,7 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillDatasetWithoutFieldIsIgnored() throws Exception {
// Set service.
enableService();
@@ -791,7 +793,7 @@
}
@Test
- @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillCallbacks() is enough")
public void testAutofillCallbackDisabled() throws Exception {
// Set service.
disableService();
@@ -807,13 +809,13 @@
}
@Test
- @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillCallbacks() is enough")
public void testAutofillCallbackNoDatasets() throws Exception {
callbackUnavailableTest(NO_RESPONSE);
}
@Test
- @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillCallbacks() is enough")
public void testAutofillCallbackNoDatasetsButSaveInfo() throws Exception {
callbackUnavailableTest(new CannedFillResponse.Builder()
.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
@@ -1030,19 +1032,19 @@
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillMultipleDatasetsPickFirst() throws Exception {
multipleDatasetsTest(1);
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillMultipleDatasetsPickSecond() throws Exception {
multipleDatasetsTest(2);
}
@Test
- @AppModeFull // testAutoFillOneDataset() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutoFillMultipleDatasetsPickThird() throws Exception {
multipleDatasetsTest(3);
}
@@ -1146,7 +1148,7 @@
* and password) and the dataset itself, and each dataset has the same number of fields.
*/
@Test
- @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
public void testAutofillMultipleDatasetsCustomPresentations() throws Exception {
// Set service.
enableService();
@@ -1191,7 +1193,7 @@
* and password), and each dataset has the same number of fields.
*/
@Test
- @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
public void testAutofillMultipleDatasetsCustomPresentationSameFields() throws Exception {
// Set service.
enableService();
@@ -1235,7 +1237,7 @@
* and password), but each dataset has a different number of fields.
*/
@Test
- @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
public void testAutofillMultipleDatasetsCustomPresentationFirstDatasetMissingSecondField()
throws Exception {
// Set service.
@@ -1278,7 +1280,7 @@
* and password), but each dataset has a different number of fields.
*/
@Test
- @AppModeFull // testAutofillOneDatasetCustomPresentation() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough")
public void testAutofillMultipleDatasetsCustomPresentationSecondDatasetMissingFirstField()
throws Exception {
// Set service.
@@ -1317,13 +1319,13 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveOnly() throws Exception {
saveOnlyTest(false);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveOnlyTriggeredManually() throws Exception {
saveOnlyTest(false);
}
@@ -1441,13 +1443,13 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveOnlyPreFilled() throws Exception {
saveOnlyTestPreFilled(false);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveOnlyTriggeredManuallyPreFilled() throws Exception {
saveOnlyTestPreFilled(true);
}
@@ -1506,7 +1508,7 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveOnlyTwoRequiredFieldsOnePrefilled() throws Exception {
enableService();
@@ -1553,7 +1555,7 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveOnlyOptionalField() throws Exception {
enableService();
@@ -1596,19 +1598,19 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveNoRequiredField_NoneFilled() throws Exception {
optionalOnlyTest(FilledFields.NONE);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveNoRequiredField_OneFilled() throws Exception {
optionalOnlyTest(FilledFields.USERNAME_ONLY);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSaveNoRequiredField_BothFilled() throws Exception {
optionalOnlyTest(FilledFields.BOTH);
}
@@ -1677,37 +1679,37 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testGenericSave() throws Exception {
customizedSaveTest(SAVE_DATA_TYPE_GENERIC);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testCustomizedSavePassword() throws Exception {
customizedSaveTest(SAVE_DATA_TYPE_PASSWORD);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testCustomizedSaveAddress() throws Exception {
customizedSaveTest(SAVE_DATA_TYPE_ADDRESS);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testCustomizedSaveCreditCard() throws Exception {
customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testCustomizedSaveUsername() throws Exception {
customizedSaveTest(SAVE_DATA_TYPE_USERNAME);
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testCustomizedSaveEmailAddress() throws Exception {
customizedSaveTest(SAVE_DATA_TYPE_EMAIL_ADDRESS);
}
@@ -1796,7 +1798,7 @@
}
@Test
- @AppModeFull // Service-specific test
+ @AppModeFull(reason = "Service-specific test")
public void testDisableSelf() throws Exception {
enableService();
@@ -1903,7 +1905,7 @@
}
@Test
- @AppModeFull // Unit test
+ @AppModeFull(reason = "Unit test")
public void testGetTextInputType() throws Exception {
// Set service.
enableService();
@@ -1926,7 +1928,7 @@
}
@Test
- @AppModeFull // Unit test
+ @AppModeFull(reason = "Unit test")
public void testNoContainers() throws Exception {
// Set service.
enableService();
@@ -1994,6 +1996,7 @@
}
@Test
+ @AppModeFull(reason = "testAutoFillOneDataset() is enough")
public void testAutofillManuallyOneDatasetWhenClipboardFull() throws Exception {
// Set service.
enableService();
@@ -2030,13 +2033,13 @@
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
autofillManuallyTwoDatasets(true);
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
autofillManuallyTwoDatasets(false);
}
@@ -2080,7 +2083,7 @@
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyPartialField() throws Exception {
// Set service.
enableService();
@@ -2115,7 +2118,7 @@
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyAgainAfterAutomaticallyAutofilledBefore() throws Exception {
// Set service.
enableService();
@@ -2176,7 +2179,7 @@
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyAgainAfterManuallyAutofilledBefore() throws Exception {
// Set service.
enableService();
@@ -2449,13 +2452,13 @@
// TODO(b/70682223): add a new test to make sure service with BIND_AUTOFILL permission works
@Test
- @AppModeFull // Service-specific test
+ @AppModeFull(reason = "Service-specific test")
public void testServiceIsDisabledWhenNewServiceInfoIsInvalid() throws Exception {
serviceIsDisabledWhenNewServiceIsInvalid(BadAutofillService.SERVICE_NAME);
}
@Test
- @AppModeFull // Service-specific test
+ @AppModeFull(reason = "Service-specific test")
public void testServiceIsDisabledWhenNewServiceNameIsInvalid() throws Exception {
serviceIsDisabledWhenNewServiceIsInvalid("Y_U_NO_VALID");
}
@@ -2587,7 +2590,7 @@
}
@Test
- @AppModeFull // Unit test
+ @AppModeFull(reason = "Unit test")
public void testNewTextAttributes() throws Exception {
enableService();
sReplier.addResponse(NO_RESPONSE);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java
index bc8ed9f..e612161 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginWithStringsActivityTest.java
@@ -42,7 +42,7 @@
import org.junit.Test;
-@AppModeFull // LoginActivityTest is enough to test ephemeral apps support
+@AppModeFull(reason = "LoginActivityTest is enough")
public class LoginWithStringsActivityTest
extends AutoFillServiceTestCase.AutoActivityLaunch<LoginWithStringsActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
index 0da2208..590f1b9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LuhnChecksumValidatorTest.java
@@ -32,7 +32,7 @@
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class LuhnChecksumValidatorTest {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
index 3d042f1..eaf60ba 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultiScreenLoginTest.java
@@ -33,6 +33,7 @@
import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
import android.content.ComponentName;
import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
import android.service.autofill.CharSequenceTransformation;
import android.service.autofill.SaveInfo;
import android.support.test.uiautomator.UiObject2;
@@ -47,6 +48,7 @@
/**
* Test case for the senario where a login screen is split in multiple activities.
*/
+@AppModeFull(reason = "Service-specific test")
public class MultiScreenLoginTest
extends AutoFillServiceTestCase.AutoActivityLaunch<UsernameOnlyActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java
index d8b263a..885376a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultiWindowLoginActivityTest.java
@@ -41,7 +41,7 @@
import java.util.concurrent.TimeoutException;
-@AppModeFull // This test requires android.permission.MANAGE_ACTIVITY_STACKS
+@AppModeFull(reason = "This test requires android.permission.MANAGE_ACTIVITY_STACKS")
public class MultiWindowLoginActivityTest
extends AutoFillServiceTestCase.AutoActivityLaunch<MultiWindowLoginActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java b/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java
index a7918c9..0ebd0a4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OnClickActionTest.java
@@ -46,7 +46,7 @@
/**
* Integration tests for the {@link OnClickAction} implementations.
*/
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class OnClickActionTest
extends AutoFillServiceTestCase.AutoActivityLaunch<SimpleSaveActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
index fe49410..c9cec8b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
@@ -46,7 +46,7 @@
* <li>Favorite Color: don't care - LOL
* </ul>
*/
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class OptionalSaveActivityTest
extends AutoFillServiceTestCase.AutoActivityLaunch<OptionalSaveActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index 767c56d..6fd973e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -55,7 +55,7 @@
/**
* Test case for an activity containing multiple partitions.
*/
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class PartitionedActivityTest extends AbstractGridActivityTestCase {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
index c476722..fd392d5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
@@ -35,7 +35,7 @@
/**
* Covers scenarios where the behavior is different because some fields were pre-filled.
*/
-@AppModeFull // LoginActivityTest is enough to test ephemeral apps support
+@AppModeFull(reason = "LoginActivityTest is enough")
public class PreFilledLoginActivityTest
extends AutoFillServiceTestCase.AutoActivityLaunch<PreFilledLoginActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java
index f0e68a6..cc26ec5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/RegexValidatorTest.java
@@ -34,7 +34,7 @@
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class RegexValidatorTest {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java b/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
index 1c009e9..4812574 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SaveInfoTest.java
@@ -36,7 +36,7 @@
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class SaveInfoTest {
private final AutofillId mId = new AutofillId(42);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java b/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java
index a27a5bd..2d5c722 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ServiceDisabledForSureTest.java
@@ -22,6 +22,7 @@
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.view.autofill.AutofillManager;
@@ -31,6 +32,7 @@
/**
* Test case that guarantee the service is disabled before the activity launches.
*/
+@AppModeFull(reason = "Service-specific test")
public class ServiceDisabledForSureTest
extends AutoFillServiceTestCase.AutoActivityLaunch<OnCreateServiceStatusVerifierActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index b9bd41a..d93e3bde 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -62,7 +62,7 @@
/**
* Test the lifecycle of a autofill session
*/
-@AppModeFull // This test requires android.permission.WRITE_EXTERNAL_STORAGE
+@AppModeFull(reason = "This test requires android.permission.WRITE_EXTERNAL_STORAGE")
public class SessionLifecycleTest extends AutoFillServiceTestCase.ManualActivityLaunch {
private static final String TAG = "SessionLifecycleTest";
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java b/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
index 1ab9069..22ba3b9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SettingsIntentTest.java
@@ -29,7 +29,7 @@
import org.junit.After;
import org.junit.Test;
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class SettingsIntentTest
extends AutoFillServiceTestCase.AutoActivityLaunch<TrampolineForResultActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
index 93ff57b..cec472e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
@@ -137,6 +137,7 @@
}
@Test
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testAutoFillOneDatasetAndSave_largeAssistStructure() throws Exception {
startActivity();
@@ -249,7 +250,7 @@
}
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testSave() throws Exception {
saveTest(false);
}
@@ -312,7 +313,7 @@
* Emulates an app dyanmically adding the password field after username is typed.
*/
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testPartitionedSave() throws Exception {
startActivity();
@@ -369,7 +370,7 @@
* Emulates an app using fragments to display username and password in 2 steps.
*/
@Test
- @AppModeFull // testAutoFillOneDatasetAndSave() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
public void testDelayedSave() throws Exception {
startActivity();
@@ -941,7 +942,7 @@
}
@Test
- @AppModeFull // Service-specific test
+ @AppModeFull(reason = "Service-specific test")
public void testSelectedDatasetsAreSentOnSaveRequest() throws Exception {
startActivity();
@@ -1098,7 +1099,7 @@
}
@Test
- @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
public void testSanitizeOnSaveNoChange() throws Exception {
startActivity();
@@ -1136,7 +1137,7 @@
}
@Test
- @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
public void testDontSaveWhenSanitizedValueForRequiredFieldDidntChange() throws Exception {
startActivity();
@@ -1174,7 +1175,7 @@
}
@Test
- @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
public void testDontSaveWhenSanitizedValueForOptionalFieldDidntChange() throws Exception {
startActivity();
@@ -1208,7 +1209,7 @@
}
@Test
- @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
public void testDontSaveWhenRequiredFieldFailedSanitization() throws Exception {
startActivity();
@@ -1243,7 +1244,7 @@
}
@Test
- @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
public void testDontSaveWhenOptionalFieldFailedSanitization() throws Exception {
startActivity();
@@ -1279,7 +1280,7 @@
}
@Test
- @AppModeFull // testSanitizeOnSaveWhenAppChangeValues() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSanitizeOnSaveWhenAppChangeValues() is enough")
public void testDontSaveWhenInitialValueAndNoUserInputAndServiceDatasets() throws Throwable {
// Prepare activitiy.
startActivity();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java b/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java
index 2b6d5c6..1c9c246 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TextValueSanitizerTest.java
@@ -31,7 +31,7 @@
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class TextValueSanitizerTest {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
index c7f3480..f07d994 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
@@ -17,7 +17,7 @@
import android.platform.test.annotations.AppModeFull;
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class TimePickerClockActivityTest extends TimePickerTestCase<TimePickerClockActivity> {
@Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
index a6ac44f..9245387 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
@@ -17,7 +17,7 @@
import android.platform.test.annotations.AppModeFull;
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class TimePickerSpinnerActivityTest extends TimePickerTestCase<TimePickerSpinnerActivity> {
@Override
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
index b65b91b..44027ef 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
@@ -26,6 +26,8 @@
private static final long ONE_TIMEOUT_TO_RULE_THEN_ALL_MS = 20_000;
private static final long ONE_NAPTIME_TO_RULE_THEN_ALL_MS = 2_000;
+ static final long MOCK_IME_TIMEOUT_MS = 5_000;
+
/**
* Timeout until framework binds / unbinds from service.
*/
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
index e0c2894..d0a675a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
@@ -42,7 +42,7 @@
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class UserDataTest {
private static final Context sContext = InstrumentationRegistry.getContext();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java b/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
index 85c6737..522fd98 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ValidatorTest.java
@@ -37,7 +37,7 @@
/**
* Simple integration test to verify that the UI is only shown if the validator passes.
*/
-@AppModeFull // Service-specific test
+@AppModeFull(reason = "Service-specific test")
public class ValidatorTest extends AbstractLoginActivityTestCase {
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java b/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java
index bb4561b..63e2e3c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ValidatorsTest.java
@@ -38,7 +38,7 @@
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class ValidatorsTest {
@Mock private Validator mInvalidValidator;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index 8c88928..5b9c646 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -37,7 +37,7 @@
import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
-@AppModeFull // Unit test
+@AppModeFull(reason = "Unit test")
public class ViewAttributesTest
extends AutoFillServiceTestCase.AutoActivityLaunch<ViewAttributesTestActivity> {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
index 72688f6..af21337 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
@@ -121,7 +121,7 @@
}
@Test
- @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
public void testMultipleUrlBars_bothExist() throws Exception {
SettingsUtils.syncSet(sContext, NAMESPACE_GLOBAL, AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
SERVICE_PACKAGE + "[my_url_bar,my_url_bar2]");
@@ -148,7 +148,7 @@
}
@Test
- @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
public void testFocusOnUrlBarIsIgnored() throws Throwable {
// Set service.
enableService();
@@ -170,7 +170,7 @@
}
@Test
- @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
public void testUrlBarChangeIgnoredWhenServiceCanSave() throws Throwable {
// Set service.
enableService();
@@ -223,7 +223,7 @@
}
@Test
- @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
public void testUrlBarChangeCancelSessionWhenServiceCannotSave() throws Throwable {
// Set service.
enableService();
@@ -263,7 +263,7 @@
}
@Test
- @AppModeFull // testMultipleUrlBars_firstDoesNotExist() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testMultipleUrlBars_firstDoesNotExist() is enough")
public void testUrlBarChangeCancelSessionWhenServiceReturnsNullResponse() throws Throwable {
// Set service.
enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index 07557bf..8cd9a67 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -113,7 +113,7 @@
}
@Test
- @AppModeFull // testAutofillSync() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillSync() is enough")
public void testAutofillAsync() throws Exception {
skipTestOnCompatMode();
@@ -251,7 +251,7 @@
}
@Test
- @AppModeFull // testAutofillSync() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillSync() is enough")
public void testAutofillTwoDatasets() throws Exception {
// Set service.
enableService();
@@ -324,13 +324,13 @@
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
autofillManuallyTwoDatasets(true);
}
@Test
- @AppModeFull // testAutofillManuallyOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough")
public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
autofillManuallyTwoDatasets(false);
}
@@ -402,7 +402,7 @@
}
@Test
- @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillCallbacks() is enough")
public void testAutofillCallbackDisabled() throws Throwable {
// Set service.
disableService();
@@ -416,7 +416,7 @@
}
@Test
- @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillCallbacks() is enough")
public void testAutofillCallbackNoDatasets() throws Throwable {
// Set service.
enableService();
@@ -437,7 +437,7 @@
}
@Test
- @AppModeFull // testAutofillCallbacks() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillCallbacks() is enough")
public void testAutofillCallbackNoDatasetsButSaveInfo() throws Throwable {
// Set service.
enableService();
@@ -628,7 +628,7 @@
}
@Test
- @AppModeFull // testSaveNotShown_noUserInput() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSaveNotShown_noUserInput() is enough")
public void testSaveNotShown_initialValues_noUserInput() throws Throwable {
// Prepare activitiy.
mActivity.mUsername.setText("foo");
@@ -653,7 +653,7 @@
}
@Test
- @AppModeFull // testSaveNotShown_noUserInput() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSaveNotShown_noUserInput() is enough")
public void testSaveNotShown_initialValues_noUserInput_serviceDatasets() throws Throwable {
// Prepare activitiy.
mActivity.mUsername.setText("foo");
@@ -684,7 +684,7 @@
}
@Test
- @AppModeFull // testSaveNotShown_noUserInput() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testSaveNotShown_noUserInput() is enough")
public void testSaveNotShown_userInputMatchesDatasets() throws Throwable {
// Prepare activitiy.
mActivity.mUsername.setText("foo");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
index 4712413..637d8b4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
@@ -67,7 +67,7 @@
}
@Test
- @AppModeFull // testAutofillOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillOneDataset() is enough")
public void testAutofillNoDatasets() throws Exception {
// Set service.
enableService();
@@ -93,7 +93,7 @@
@Ignore("blocked on b/74793485")
@Test
- @AppModeFull // testAutofillOneDataset() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillOneDataset() is enough")
public void testAutofillOneDataset_usingAppContext() throws Exception {
autofillOneDatasetTest(true);
}
@@ -297,7 +297,7 @@
}
@Test
- @AppModeFull // testAutofillAndSave() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillAndSave() is enough")
public void testAutofillAndSave_withExternalViews_loadWebViewFirst() throws Exception {
// Set service.
enableService();
@@ -423,7 +423,7 @@
@Test
@Ignore("blocked on b/69461853")
- @AppModeFull // testAutofillAndSave() is enough to test ephemeral apps support
+ @AppModeFull(reason = "testAutofillAndSave() is enough")
public void testAutofillAndSave_withExternalViews_loadExternalViewsFirst() throws Exception {
// Set service.
enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
index a4d189f..9deb6ed 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
@@ -26,6 +26,7 @@
import android.autofillservice.cts.LoginActivity;
import android.autofillservice.cts.OneTimeCancellationSignalListener;
import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedFillRequest;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.uiautomator.UiObject2;
import android.view.View;
import android.view.autofill.AutofillId;
@@ -52,6 +53,7 @@
}
@Test
+ @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
public void testAutoFill_neitherServiceCanAutofill() throws Exception {
// Set services
enableService();
@@ -118,6 +120,7 @@
}
@Test
+ @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
public void testAutoFill_mainServiceReturnedNull_augmentedAutofillTwoFields() throws Exception {
// Set services
enableService();
@@ -158,6 +161,7 @@
@Ignore("blocked on b/122728762")
@Test
+ @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
public void testCancellationSignalCalledAfterTimeout() throws Exception {
// Set services
enableService();
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index 9ab8222..7dac96f 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -653,22 +653,46 @@
}
int64_t getMinFrameDurationFor(int64_t format, int64_t width, int64_t height) {
- return getDurationFor(ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, format, width, height);
+ int32_t minFrameDurationTag = (format == AIMAGE_FORMAT_HEIC) ?
+ ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS :
+ ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+ return getDurationFor(minFrameDurationTag, format, width, height);
}
int64_t getStallDurationFor(int64_t format, int64_t width, int64_t height) {
- return getDurationFor(ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS, format, width, height);
+ int32_t stallDurationTag = (format == AIMAGE_FORMAT_HEIC) ?
+ ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS :
+ ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS;
+ return getDurationFor(stallDurationTag, format, width, height);
}
bool getMaxSizeForFormat(int32_t format, int32_t *width, int32_t *height) {
ACameraMetadata_const_entry entry;
- ACameraMetadata_getConstEntry(mChars,
- ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+
+ int32_t streamConfigTag, streamConfigOutputTag;
+ switch (format) {
+ case AIMAGE_FORMAT_HEIC:
+ streamConfigTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS;
+ streamConfigOutputTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT;
+ break;
+ case AIMAGE_FORMAT_JPEG:
+ case AIMAGE_FORMAT_Y8:
+ default:
+ streamConfigTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ streamConfigOutputTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+ break;
+ }
+
bool supported = false;
- int32_t w = 0, h = 0;
+ camera_status_t status = ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
+ if (status == ACAMERA_ERROR_METADATA_NOT_FOUND) {
+ return supported;
+ }
+
+ int32_t w = 0, h = 0;
for (uint32_t i = 0; i < entry.count; i += 4) {
if (entry.data.i32[i] == format &&
- entry.data.i32[i+3] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ entry.data.i32[i+3] == streamConfigOutputTag &&
entry.data.i32[i+1] * entry.data.i32[i+2] > w * h) {
w = entry.data.i32[i+1];
h = entry.data.i32[i+2];
@@ -685,11 +709,25 @@
bool isSizeSupportedForFormat(int32_t format, int32_t width, int32_t height) {
ACameraMetadata_const_entry entry;
- ACameraMetadata_getConstEntry(mChars,
- ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+
+ int32_t streamConfigTag, streamConfigOutputTag;
+ switch (format) {
+ case AIMAGE_FORMAT_HEIC:
+ streamConfigTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS;
+ streamConfigOutputTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT;
+ break;
+ case AIMAGE_FORMAT_JPEG:
+ case AIMAGE_FORMAT_Y8:
+ default:
+ streamConfigTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ streamConfigOutputTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+ break;
+ }
+
+ ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
for (uint32_t i = 0; i < entry.count; i += 4) {
if (entry.data.i32[i] == format &&
- entry.data.i32[i+3] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ entry.data.i32[i+3] == streamConfigOutputTag &&
entry.data.i32[i+1] == width &&
entry.data.i32[i+2] == height) {
return true;
@@ -702,7 +740,9 @@
if (tag != ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS &&
tag != ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS &&
tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS &&
- tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS) {
+ tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS &&
+ tag != ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS &&
+ tag != ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS) {
return -1;
}
ACameraMetadata_const_entry entry;
@@ -2860,6 +2900,7 @@
testHeight = TEST_HEIGHT;
break;
case AIMAGE_FORMAT_Y8:
+ case AIMAGE_FORMAT_HEIC:
if (!staticInfo.getMaxSizeForFormat(format, &testWidth, &testHeight)) {
// This isn't an error condition: device does't support this
// format.
@@ -2956,13 +2997,13 @@
}
int64_t minFrameDurationNs = staticInfo.getMinFrameDurationFor(
- AIMAGE_FORMAT_JPEG, TEST_WIDTH, TEST_HEIGHT);
+ format, testWidth, testHeight);
if (minFrameDurationNs < 0) {
LOG_ERROR(errorString, "Get camera %s minFrameDuration failed", cameraId);
goto cleanup;
}
- int64_t stallDurationNs = staticInfo.getStallDurationFor(
- AIMAGE_FORMAT_JPEG, TEST_WIDTH, TEST_HEIGHT);
+ int64_t stallDurationNs = (format == AIMAGE_FORMAT_Y8) ? 0 :
+ staticInfo.getStallDurationFor(format, testWidth, testHeight);
if (stallDurationNs < 0) {
LOG_ERROR(errorString, "Get camera %s stallDuration failed", cameraId);
goto cleanup;
@@ -3053,6 +3094,15 @@
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeImageReaderTest_\
+testHeicNative(
+ JNIEnv* env, jclass /*clazz*/, jstring jOutPath) {
+ ALOGV("%s", __FUNCTION__);
+ return nativeImageReaderTestBase(env, jOutPath, AIMAGE_FORMAT_HEIC,
+ ImageReaderListener::validateImageCb);
+}
+
+extern "C" jboolean
+Java_android_hardware_camera2_cts_NativeImageReaderTest_\
testImageReaderCloseAcquiredImagesNative(
JNIEnv* env, jclass /*clazz*/) {
ALOGV("%s", __FUNCTION__);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index b095b8a..8eff888 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -187,6 +187,7 @@
boolean isMonochromeWithY8 = arrayContains(actualCapabilities, MONOCHROME)
&& arrayContains(outputFormats, ImageFormat.Y8);
+ boolean supportHeic = arrayContains(outputFormats, ImageFormat.HEIC);
assertArrayContains(
String.format("No valid YUV_420_888 preview formats found for: ID %s",
@@ -202,6 +203,7 @@
Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888);
Size[] y8Sizes = config.getOutputSizes(ImageFormat.Y8);
Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG);
+ Size[] heicSizes = config.getOutputSizes(ImageFormat.HEIC);
Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE);
CameraTestUtils.assertArrayNotEmpty(yuvSizes,
@@ -224,6 +226,12 @@
"Required FULLHD size not found for format %x for: ID %s",
ImageFormat.JPEG, mIds[counter]), jpegSizes,
new Size[] {FULLHD, FULLHD_ALT});
+ if (supportHeic) {
+ assertArrayContainsAnyOf(String.format(
+ "Required FULLHD size not found for format %x for: ID %s",
+ ImageFormat.HEIC, mIds[counter]), heicSizes,
+ new Size[] {FULLHD, FULLHD_ALT});
+ }
}
if (activeArraySize.getWidth() >= HD.getWidth() &&
@@ -231,6 +239,11 @@
assertArrayContains(String.format(
"Required HD size not found for format %x for: ID %s",
ImageFormat.JPEG, mIds[counter]), jpegSizes, HD);
+ if (supportHeic) {
+ assertArrayContains(String.format(
+ "Required HD size not found for format %x for: ID %s",
+ ImageFormat.HEIC, mIds[counter]), heicSizes, HD);
+ }
}
if (activeArraySize.getWidth() >= VGA.getWidth() &&
@@ -238,6 +251,11 @@
assertArrayContains(String.format(
"Required VGA size not found for format %x for: ID %s",
ImageFormat.JPEG, mIds[counter]), jpegSizes, VGA);
+ if (supportHeic) {
+ assertArrayContains(String.format(
+ "Required VGA size not found for format %x for: ID %s",
+ ImageFormat.HEIC, mIds[counter]), heicSizes, VGA);
+ }
}
if (activeArraySize.getWidth() >= QVGA.getWidth() &&
@@ -245,6 +263,12 @@
assertArrayContains(String.format(
"Required QVGA size not found for format %x for: ID %s",
ImageFormat.JPEG, mIds[counter]), jpegSizes, QVGA);
+ if (supportHeic) {
+ assertArrayContains(String.format(
+ "Required QVGA size not found for format %x for: ID %s",
+ ImageFormat.HEIC, mIds[counter]), heicSizes, QVGA);
+ }
+
}
ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes));
@@ -1363,6 +1387,8 @@
CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
Rect activeArray = c.get(
CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ float jpegAspectRatioThreshold = .01f;
+ boolean jpegSizeMatch = false;
// Verify pre-correction array encloses active array
mCollector.expectTrue("preCorrectionArray [" + precorrectionArray.left + ", " +
@@ -1392,6 +1418,7 @@
hasDepth16);
if (hasDepth16) {
Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16);
+ Size[] jpegSizes = configs.getOutputSizes(ImageFormat.JPEG);
mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!",
depthSizes != null && depthSizes.length > 0);
if (depthSizes != null) {
@@ -1408,6 +1435,24 @@
mCollector.expectTrue("Non-negative stall duration for depth size "
+ depthSize + " expected, got " + stallDuration,
stallDuration >= 0);
+ if ((jpegSizes != null) && (!jpegSizeMatch)) {
+ for (Size jpegSize : jpegSizes) {
+ if (jpegSize.equals(depthSize)) {
+ jpegSizeMatch = true;
+ break;
+ } else {
+ float depthAR = (float) depthSize.getWidth() /
+ (float) depthSize.getHeight();
+ float jpegAR = (float) jpegSize.getWidth() /
+ (float) jpegSize.getHeight();
+ if (Math.abs(depthAR - jpegAR) <=
+ jpegAspectRatioThreshold) {
+ jpegSizeMatch = true;
+ break;
+ }
+ }
+ }
+ }
}
}
}
@@ -1446,6 +1491,8 @@
mCollector.expectTrue("Supports DEPTH_JPEG " +
"but no sizes for DEPTH_JPEG supported!",
depthJpegSizes != null && depthJpegSizes.length > 0);
+ mCollector.expectTrue("Supports DEPTH_JPEG but there are no JPEG sizes with" +
+ " matching DEPTH16 aspect ratio", jpegSizeMatch);
if (depthJpegSizes != null) {
for (Size depthJpegSize : depthJpegSizes) {
mCollector.expectTrue("All depth jpeg sizes must be nonzero",
@@ -1462,6 +1509,11 @@
stallDuration >= 0);
}
}
+ } else {
+ boolean canSupportDynamicDepth = jpegSizeMatch && !depthIsExclusive;
+ mCollector.expectTrue("Device must support DEPTH_JPEG, please check whether " +
+ "library libdepthphoto.so is part of the device PRODUCT_PACKAGES",
+ !canSupportDynamicDepth);
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
index af6e5e0..0716c24 100644
--- a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
@@ -91,7 +91,7 @@
SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
prepareStillCaptureAndStartPreview(previewRequest, stillCaptureRequest,
- previewSize, stillSize, resultListener, imageListener);
+ previewSize, stillSize, resultListener, imageListener, false /*isHeic*/);
CaptureResult result = resultListener.getCaptureResult(WAIT_FOR_FRAMES_TIMEOUT_MS);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
index e275aa4..b8cf221 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -204,6 +204,17 @@
}
}
+ public void testHeic() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ Log.v(TAG, "Testing heic capture for Camera " + id);
+ openDevice(id);
+ bufferFormatTestByCamera(ImageFormat.HEIC, /*repeating*/false);
+ } finally {
+ closeDevice(id);
+ }
+ }
+ }
public void testRepeatingJpeg() throws Exception {
for (String id : mCameraIds) {
@@ -243,6 +254,18 @@
}
}
+ public void testRepeatingHeic() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ Log.v(TAG, "Testing repeating heic capture for Camera " + id);
+ openDevice(id);
+ bufferFormatTestByCamera(ImageFormat.HEIC, /*repeating*/true);
+ } finally {
+ closeDevice(id);
+ }
+ }
+ }
+
public void testLongProcessingRepeatingRaw() throws Exception {
for (String id : mCameraIds) {
try {
diff --git a/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java
index 4eee734..ce5f946 100644
--- a/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/NativeImageReaderTest.java
@@ -43,6 +43,11 @@
testY8Native(mDebugFileNameBase));
}
+ public void testHeic() {
+ assertTrue("testHeic fail, see log for details",
+ testHeicNative(mDebugFileNameBase));
+ }
+
public void testImageReaderCloseAcquiredImages() {
assertTrue("testImageReaderClose fail, see log for details",
testImageReaderCloseAcquiredImagesNative());
@@ -50,5 +55,6 @@
private static native boolean testJpegNative(String filePath);
private static native boolean testY8Native(String filePath);
+ private static native boolean testHeicNative(String filePath);
private static native boolean testImageReaderCloseAcquiredImagesNative();
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 0fa1741..fbb8cce 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -363,7 +363,8 @@
readers = prepareStillCaptureAndStartPreview(previewBuilder, captureBuilder,
mOrderedPreviewSizes.get(0), imageSizes, formats,
- previewResultListener, NUM_MAX_IMAGES, imageListeners);
+ previewResultListener, NUM_MAX_IMAGES, imageListeners,
+ false /*isHeic*/);
if (addPreviewDelay) {
Thread.sleep(500);
@@ -1141,11 +1142,13 @@
* @param resultListener Capture result listener
* @param maxNumImages The max number of images set to the image reader
* @param imageListeners The single capture capture image listeners
+ * @param isHeic Capture HEIC image if true, JPEG image if false
*/
private ImageReader[] prepareStillCaptureAndStartPreview(
CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest,
Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener,
- int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners)
+ int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners,
+ boolean isHeic)
throws Exception {
if ((captureSizes == null) || (formats == null) || (imageListeners == null) &&
diff --git a/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
index 8fa1077..1420078 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
@@ -116,6 +116,24 @@
}
/**
+ * Test YUV_420_888 -> HEIC with maximal supported sizes
+ */
+ @Test
+ public void testBasicYuvToHeicReprocessing() throws Exception {
+ for (String id : mCameraIds) {
+ if (!isYuvReprocessSupported(id)) {
+ continue;
+ }
+ if (!mAllStaticInfo.get(id).isHeicSupported()) {
+ continue;
+ }
+
+ // YUV_420_888 -> HEIC must be supported.
+ testBasicReprocessing(id, ImageFormat.YUV_420_888, ImageFormat.HEIC);
+ }
+ }
+
+ /**
* Test OPAQUE -> YUV_420_888 with maximal supported sizes
*/
@Test
@@ -146,6 +164,24 @@
}
/**
+ * Test OPAQUE -> HEIC with maximal supported sizes
+ */
+ @Test
+ public void testBasicOpaqueToHeicReprocessing() throws Exception {
+ for (String id : mCameraIds) {
+ if (!isOpaqueReprocessSupported(id)) {
+ continue;
+ }
+ if (!mAllStaticInfo.get(id).isHeicSupported()) {
+ continue;
+ }
+
+ // OPAQUE -> HEIC must be supported.
+ testBasicReprocessing(id, ImageFormat.PRIVATE, ImageFormat.HEIC);
+ }
+ }
+
+ /**
* Test all supported size and format combinations.
*/
@Test(timeout=60*60*1000) // timeout = 60 mins for long running tests
@@ -978,7 +1014,7 @@
Image image = getReprocessOutputImageReaderListener().getImage(CAPTURE_TIMEOUT_MS);
verifyJpegKeys(image, reprocessResults[i], reprocessOutputSize,
testThumbnailSizes[i], EXIF_TEST_DATA[i], mStaticInfo, mCollector,
- mDebugFileNameBase);
+ mDebugFileNameBase, ImageFormat.JPEG);
image.close();
}
@@ -1391,6 +1427,9 @@
case ImageFormat.JPEG:
filename += ".jpg";
break;
+ case ImageFormat.HEIC:
+ filename += ".heic";
+ break;
case ImageFormat.NV16:
case ImageFormat.NV21:
case ImageFormat.YUV_420_888:
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index 995a2c7..a519101 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -254,8 +254,10 @@
private void setupConfigurationTargets(List<MandatoryStreamInformation> streamsInfo,
List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
List<ImageReader> yuvTargets, List<ImageReader> y8Targets,
- List<ImageReader> rawTargets, List<OutputConfiguration> outputConfigs,
- int numBuffers, boolean substituteY8, MandatoryStreamInformation overrideStreamInfo,
+ List<ImageReader> rawTargets, List<ImageReader> heicTargets,
+ List<OutputConfiguration> outputConfigs,
+ int numBuffers, boolean substituteY8, boolean substituteHeic,
+ MandatoryStreamInformation overrideStreamInfo,
List<String> overridePhysicalCameraIds, List<Size> overridePhysicalCameraSizes) {
ImageDropperListener imageDropperListener = new ImageDropperListener();
@@ -267,6 +269,8 @@
int format = streamInfo.getFormat();
if (substituteY8 && (format == ImageFormat.YUV_420_888)) {
format = ImageFormat.Y8;
+ } else if (substituteHeic && (format == ImageFormat.JPEG)) {
+ format = ImageFormat.HEIC;
}
Surface newSurface;
Size[] availableSizes = new Size[streamInfo.getAvailableSizes().size()];
@@ -345,6 +349,18 @@
}
break;
}
+ case ImageFormat.HEIC: {
+ ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
+ targetSize.getHeight(), format, numBuffers);
+ target.setOnImageAvailableListener(imageDropperListener, mHandler);
+ OutputConfiguration config = new OutputConfiguration(target.getSurface());
+ if (numConfigs > 1) {
+ config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+ }
+ outputConfigs.add(config);
+ heicTargets.add(target);
+ break;
+ }
default:
fail("Unknown output format " + format);
}
@@ -366,13 +382,36 @@
}
}
+ // Check whether substituting JPEG format with HEIC format
+ boolean substituteHeic = false;
+ if (mStaticInfo.isHeicSupported()) {
+ List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
+ for (MandatoryStreamInformation streamInfo : streamsInfo) {
+ if (streamInfo.getFormat() == ImageFormat.JPEG) {
+ substituteHeic = true;
+ break;
+ }
+ }
+ }
+
// Test camera output combination
Log.i(TAG, "Testing mandatory stream combination: " + combination.getDescription() +
" on camera: " + cameraId);
- testMandatoryStreamCombination(cameraId, combination, /*substituteY8*/false);
+ testMandatoryStreamCombination(cameraId, combination, /*substituteY8*/false,
+ /*substituteHeic*/false);
if (substituteY8) {
- testMandatoryStreamCombination(cameraId, combination, substituteY8);
+ Log.i(TAG, "Testing mandatory stream combination: " + combination.getDescription() +
+ " on camera: " + cameraId + " with Y8");
+ testMandatoryStreamCombination(cameraId, combination, /*substituteY8*/true,
+ /*substituteHeic*/false);
+ }
+
+ if (substituteHeic) {
+ Log.i(TAG, "Testing mandatory stream combination: " + combination.getDescription() +
+ " on camera: " + cameraId + " with HEIC");
+ testMandatoryStreamCombination(cameraId, combination,
+ /*substituteY8*/false, /*substituteHeic*/true);
}
// Test substituting YUV_888/RAW with physical streams for logical camera
@@ -383,7 +422,7 @@
testMultiCameraOutputCombination(cameraId, combination, /*substituteY8*/false);
if (substituteY8) {
- testMultiCameraOutputCombination(cameraId, combination, substituteY8);
+ testMultiCameraOutputCombination(cameraId, combination, /*substituteY8*/true);
}
}
}
@@ -441,10 +480,12 @@
List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
List<ImageReader> y8Targets = new ArrayList<ImageReader>();
List<ImageReader> rawTargets = new ArrayList<ImageReader>();
+ List<ImageReader> heicTargets = new ArrayList<ImageReader>();
setupConfigurationTargets(streamsInfo, privTargets, jpegTargets, yuvTargets,
- y8Targets, rawTargets, outputConfigs, MIN_RESULT_COUNT, substituteY8,
- streamInfo, physicalCamerasForSize, physicalCameraSizes);
+ y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT,
+ substituteY8, /*substituteHeic*/false, streamInfo, physicalCamerasForSize,
+ physicalCameraSizes);
boolean haveSession = false;
try {
@@ -516,7 +557,8 @@
}
private void testMandatoryStreamCombination(String cameraId,
- MandatoryStreamCombination combination, boolean substituteY8) throws Exception {
+ MandatoryStreamCombination combination,
+ boolean substituteY8, boolean substituteHeic) throws Exception {
// Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
@@ -529,9 +571,11 @@
List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
List<ImageReader> y8Targets = new ArrayList<ImageReader>();
List<ImageReader> rawTargets = new ArrayList<ImageReader>();
+ List<ImageReader> heicTargets = new ArrayList<ImageReader>();
setupConfigurationTargets(combination.getStreamsInformation(), privTargets, jpegTargets,
- yuvTargets, y8Targets, rawTargets, outputConfigs, MIN_RESULT_COUNT, substituteY8,
+ yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT,
+ substituteY8, substituteHeic,
null /*overrideStreamInfo*/, null /*overridePhysicalCameraIds*/,
null /* overridePhysicalCameraSizes) */);
@@ -600,6 +644,9 @@
for (ImageReader target : rawTargets) {
target.close();
}
+ for (ImageReader target : heicTargets) {
+ target.close();
+ }
}
/**
@@ -635,26 +682,42 @@
private void testMandatoryReprocessableStreamCombination(String cameraId,
MandatoryStreamCombination combination) {
// Test reprocess stream combination
- testMandatoryReprocessableStreamCombination(cameraId, combination, /*substituteY8*/false);
+ testMandatoryReprocessableStreamCombination(cameraId, combination,
+ /*substituteY8*/false, /*substituteHeic*/false);
// Test substituting YUV_888 format with Y8 format in reprocess stream combination.
if (mStaticInfo.isMonochromeWithY8()) {
List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
- boolean hasY8 = false;
+ boolean substituteY8 = false;
for (MandatoryStreamInformation streamInfo : streamsInfo) {
if (streamInfo.getFormat() == ImageFormat.YUV_420_888) {
- hasY8 = true;
- break;
+ substituteY8 = true;
}
}
- if (hasY8) {
- testMandatoryReprocessableStreamCombination(cameraId, combination, hasY8);
+ if (substituteY8) {
+ testMandatoryReprocessableStreamCombination(cameraId, combination,
+ /*substituteY8*/true, /*substituteHeic*/false);
+ }
+ }
+
+ if (mStaticInfo.isHeicSupported()) {
+ List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
+ boolean substituteHeic = false;
+ for (MandatoryStreamInformation streamInfo : streamsInfo) {
+ if (streamInfo.getFormat() == ImageFormat.JPEG) {
+ substituteHeic = true;
+ }
+ }
+ if (substituteHeic) {
+ testMandatoryReprocessableStreamCombination(cameraId, combination,
+ /*substituteY8*/false, /*substituteHeic*/true);
}
}
}
private void testMandatoryReprocessableStreamCombination(String cameraId,
- MandatoryStreamCombination combination, boolean substituteY8) {
+ MandatoryStreamCombination combination, boolean substituteY8,
+ boolean substituteHeic) {
final int TIMEOUT_FOR_RESULT_MS = 3000;
final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3;
@@ -664,6 +727,7 @@
List<ImageReader> yuvTargets = new ArrayList<>();
List<ImageReader> y8Targets = new ArrayList<>();
List<ImageReader> rawTargets = new ArrayList<>();
+ List<ImageReader> heicTargets = new ArrayList<>();
ArrayList<Surface> outputSurfaces = new ArrayList<>();
List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
ImageReader inputReader = null;
@@ -685,13 +749,17 @@
inputFormat = ImageFormat.Y8;
}
+ Log.i(TAG, "testMandatoryReprocessableStreamCombination: " +
+ combination.getDescription() + ", substituteY8 = " + substituteY8 +
+ ", substituteHeic = " + substituteHeic);
try {
// The second stream information entry is the ZSL stream, which is configured
// separately.
setupConfigurationTargets(streamInfo.subList(2, streamInfo.size()), privTargets,
- jpegTargets, yuvTargets, y8Targets, rawTargets, outputConfigs,
- NUM_REPROCESS_CAPTURES_PER_CONFIG, substituteY8, null /*overrideStreamInfo*/,
- null /*overridePhysicalCameraIds*/, null /* overridePhysicalCameraSizes) */);
+ jpegTargets, yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs,
+ NUM_REPROCESS_CAPTURES_PER_CONFIG, substituteY8, substituteHeic,
+ null /*overrideStreamInfo*/, null /*overridePhysicalCameraIds*/,
+ null /* overridePhysicalCameraSizes) */);
outputSurfaces.ensureCapacity(outputConfigs.size());
for (OutputConfiguration config : outputConfigs) {
@@ -709,7 +777,8 @@
final boolean useY8 = inputIsY8 || y8Targets.size() > 0;
final int totalNumReprocessCaptures = NUM_REPROCESS_CAPTURES_PER_CONFIG * (
((inputIsYuv || inputIsY8) ? 1 : 0) +
- jpegTargets.size() + (useYuv ? yuvTargets.size() : y8Targets.size()));
+ (substituteHeic ? heicTargets.size() : jpegTargets.size()) +
+ (useYuv ? yuvTargets.size() : y8Targets.size()));
// It needs 1 input buffer for each reprocess capture + the number of buffers
// that will be used as outputs.
@@ -750,6 +819,10 @@
reprocessOutputs.add(reader.getSurface());
}
+ for (ImageReader reader : heicTargets) {
+ reprocessOutputs.add(reader.getSurface());
+ }
+
for (ImageReader reader : yuvTargets) {
reprocessOutputs.add(reader.getSurface());
}
@@ -803,6 +876,10 @@
target.close();
}
+ for (ImageReader target : heicTargets) {
+ target.close();
+ }
+
if (inputReader != null) {
inputReader.close();
}
@@ -1916,6 +1993,7 @@
static final int YUV = ImageFormat.YUV_420_888;
static final int RAW = ImageFormat.RAW_SENSOR;
static final int Y8 = ImageFormat.Y8;
+ static final int HEIC = ImageFormat.HEIC;
// Max resolution indices
static final int PREVIEW = 0;
@@ -1933,6 +2011,7 @@
StaticMetadata.StreamDirection.Output);
Size[] jpegSizes = sm.getJpegOutputSizesChecked();
Size[] rawSizes = sm.getRawOutputSizesChecked();
+ Size[] heicSizes = sm.getHeicOutputSizesChecked();
Size maxPreviewSize = getMaxPreviewSize(context, cameraId);
@@ -1975,6 +2054,13 @@
maxY8Sizes[MAXIMUM] = CameraTestUtils.getMaxSize(y8Sizes);
maxY8Sizes[VGA] = vgaSize;
}
+
+ if (sm.isHeicSupported()) {
+ maxHeicSizes[PREVIEW] = getMaxSize(heicSizes, maxPreviewSize);
+ maxHeicSizes[RECORD] = getMaxRecordingSize(cameraId);
+ maxHeicSizes[MAXIMUM] = CameraTestUtils.getMaxSize(heicSizes);
+ maxHeicSizes[VGA] = vgaSize;
+ }
}
Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE);
@@ -1992,6 +2078,7 @@
public final Size[] maxJpegSizes = new Size[RESOLUTION_COUNT];
public final Size[] maxYuvSizes = new Size[RESOLUTION_COUNT];
public final Size[] maxY8Sizes = new Size[RESOLUTION_COUNT];
+ public final Size[] maxHeicSizes = new Size[RESOLUTION_COUNT];
public final Size maxRawSize;
// TODO: support non maximum reprocess input.
public final Size maxInputPrivSize;
@@ -2119,9 +2206,10 @@
List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
List<ImageReader> y8Targets = new ArrayList<ImageReader>();
List<ImageReader> rawTargets = new ArrayList<ImageReader>();
+ List<ImageReader> heicTargets = new ArrayList<ImageReader>();
setupConfigurationTargets(config, maxSizes, privTargets, jpegTargets, yuvTargets,
- y8Targets, rawTargets, outputConfigs, MIN_RESULT_COUNT, i,
+ y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT, i,
physicalCamerasForSize, physicalCameraSizes);
boolean haveSession = false;
@@ -2196,7 +2284,8 @@
private void setupConfigurationTargets(int[] configs, MaxStreamSizes maxSizes,
List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
List<ImageReader> yuvTargets, List<ImageReader> y8Targets,
- List<ImageReader> rawTargets, List<OutputConfiguration> outputConfigs, int numBuffers,
+ List<ImageReader> rawTargets, List<ImageReader> heicTargets,
+ List<OutputConfiguration> outputConfigs, int numBuffers,
int overrideStreamIndex, List<String> overridePhysicalCameraIds,
List<Size> overridePhysicalCameraSizes) {
@@ -2241,6 +2330,20 @@
jpegTargets.add(target);
break;
}
+ case HEIC: {
+ Size targetSize = (numConfigs == 1) ? maxSizes.maxHeicSizes[sizeLimit] :
+ overridePhysicalCameraSizes.get(j);
+ ImageReader target = ImageReader.newInstance(
+ targetSize.getWidth(), targetSize.getHeight(), HEIC, numBuffers);
+ target.setOnImageAvailableListener(imageDropperListener, mHandler);
+ OutputConfiguration config = new OutputConfiguration(target.getSurface());
+ if (numConfigs > 1) {
+ config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+ }
+ outputConfigs.add(config);
+ heicTargets.add(target);
+ break;
+ }
case YUV: {
Size targetSize = (numConfigs == 1) ? maxSizes.maxYuvSizes[sizeLimit] :
overridePhysicalCameraSizes.get(j);
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index a169fee..22e2424 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -100,7 +100,46 @@
continue;
}
openDevice(mCameraIds[i]);
- jpegExifTestByCamera();
+ Size maxJpegSize = mOrderedStillSizes.get(0);
+ stillExifTestByCamera(ImageFormat.JPEG, maxJpegSize);
+ } finally {
+ closeDevice();
+ closeImageReader();
+ }
+ }
+ }
+
+ /**
+ * Test HEIC capture exif fields for each camera.
+ */
+ @Test
+ public void testHeicExif() throws Exception {
+ for (int i = 0; i < mCameraIds.length; i++) {
+ try {
+ Log.i(TAG, "Testing HEIC exif for Camera " + mCameraIds[i]);
+ if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) {
+ Log.i(TAG, "Camera " + mCameraIds[i] +
+ " does not support color outputs, skipping");
+ continue;
+ }
+ if (!mAllStaticInfo.get(mCameraIds[i]).isHeicSupported()) {
+ Log.i(TAG, "Camera " + mCameraIds[i] +
+ " does not support HEIC, skipping");
+ continue;
+ }
+
+ openDevice(mCameraIds[i]);
+
+ // Test maximum Heic size capture
+ List<Size> orderedHeicSizes = CameraTestUtils.getSupportedHeicSizes(
+ mCameraIds[i], mCameraManager, null/*bound*/);
+ Size maxHeicSize = orderedHeicSizes.get(0);
+ stillExifTestByCamera(ImageFormat.HEIC, maxHeicSize);
+
+ // Test preview size Heic capture
+ Size previewSize = mOrderedPreviewSizes.get(0);
+ stillExifTestByCamera(ImageFormat.HEIC, previewSize);
+
} finally {
closeDevice();
closeImageReader();
@@ -318,7 +357,7 @@
* Test all combination of available preview sizes and still sizes.
* <p>
* For each still capture, Only the jpeg buffer is validated, capture
- * result validation is covered by {@link #jpegExifTestByCamera} test.
+ * result validation is covered by {@link #stillExifTestByCamera} test.
* </p>
*/
@Test(timeout=60*60*1000) // timeout = 60 mins for long running tests
@@ -585,7 +624,7 @@
// Set the max number of images to number of focal lengths supported
prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
- maxStillSz, resultListener, focalLengths.length, imageListener);
+ maxStillSz, resultListener, focalLengths.length, imageListener, false /*isHeic*/);
for(float focalLength : focalLengths) {
@@ -613,7 +652,7 @@
validateJpegCapture(image, maxStillSz);
verifyJpegKeys(image, result, maxStillSz, thumbnailSize, exifTestData,
- mStaticInfo, mCollector, mDebugFileNameBase);
+ mStaticInfo, mCollector, mDebugFileNameBase, ImageFormat.JPEG);
}
}
@@ -633,7 +672,7 @@
CaptureRequest.Builder stillRequest =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
- maxStillSz, resultListener, imageListener);
+ maxStillSz, resultListener, imageListener, false /*isHeic*/);
// make sure preview is actually running
waitForNumResults(resultListener, NUM_FRAMES_WAITED);
@@ -719,7 +758,7 @@
stillRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
}
prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
- maxStillSz, resultListener, imageListener);
+ maxStillSz, resultListener, imageListener, false /*isHeic*/);
// Set AE mode to ON_AUTO_FLASH if flash is available.
if (mStaticInfo.hasFlash()) {
@@ -930,7 +969,7 @@
CaptureRequest.Builder stillRequest =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
prepareStillCaptureAndStartPreview(previewRequest, stillRequest, previewSz,
- stillSz, resultListener, imageListener);
+ stillSz, resultListener, imageListener, false /*isHeic*/);
mSession.capture(stillRequest.build(), resultListener, mHandler);
Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ?
RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS);
@@ -1049,7 +1088,7 @@
CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest,
NUM_RESULTS_WAIT_TIMEOUT);
Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
- basicValidateJpegImage(jpegImage, maxStillSz);
+ basicValidateBlobImage(jpegImage, maxStillSz, ImageFormat.JPEG);
Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateRaw16Image(rawImage, size);
verifyRawCaptureResult(multiRequest, result);
@@ -1188,17 +1227,19 @@
}
/**
- * Issue a Jpeg capture and validate the exif information.
+ * Issue a still capture and validate the exif information.
* <p>
* TODO: Differentiate full and limited device, some of the checks rely on
* per frame control and synchronization, most of them don't.
* </p>
*/
- private void jpegExifTestByCamera() throws Exception {
+ private void stillExifTestByCamera(int format, Size stillSize) throws Exception {
+ assertTrue(format == ImageFormat.JPEG || format == ImageFormat.HEIC);
+ boolean isHeic = (format == ImageFormat.HEIC);
+
Size maxPreviewSz = mOrderedPreviewSizes.get(0);
- Size maxStillSz = mOrderedStillSizes.get(0);
if (VERBOSE) {
- Log.v(TAG, "Testing JPEG exif with jpeg size " + maxStillSz.toString()
+ Log.v(TAG, "Testing exif with size " + stillSize.toString()
+ ", preview size " + maxPreviewSz);
}
@@ -1209,8 +1250,8 @@
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
- prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, maxStillSz,
- resultListener, imageListener);
+ prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize,
+ resultListener, imageListener, isHeic);
// Set the jpeg keys, then issue a capture
Size[] thumbnailSizes = mStaticInfo.getAvailableThumbnailSizesChecked();
@@ -1223,15 +1264,15 @@
for (int i = 0; i < EXIF_TEST_DATA.length; i++) {
setJpegKeys(stillBuilder, EXIF_TEST_DATA[i], testThumbnailSizes[i], mCollector);
- // Capture a jpeg image.
+ // Capture a jpeg/heic image.
CaptureRequest request = stillBuilder.build();
mSession.capture(request, resultListener, mHandler);
CaptureResult stillResult =
resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
- verifyJpegKeys(image, stillResult, maxStillSz, testThumbnailSizes[i], EXIF_TEST_DATA[i],
- mStaticInfo, mCollector, mDebugFileNameBase);
+ verifyJpegKeys(image, stillResult, stillSize, testThumbnailSizes[i], EXIF_TEST_DATA[i],
+ mStaticInfo, mCollector, mDebugFileNameBase, format);
// Free image resources
image.close();
@@ -1292,7 +1333,7 @@
// Set the max number of images to be same as the burst count, as the verification
// could be much slower than producing rate, and we don't want to starve producer.
prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
- maxStillSz, resultListener, numSteps, imageListener);
+ maxStillSz, resultListener, numSteps, imageListener, false /*isHeic*/);
for (int i = 0; i <= numSteps; i++) {
int exposureCompensation = i * stepsPerEv + compensationRange.getLower();
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 8c245bd..7a9ae93 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -285,9 +285,10 @@
protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest,
CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz,
CaptureCallback resultListener,
- ImageReader.OnImageAvailableListener imageListener) throws Exception {
+ ImageReader.OnImageAvailableListener imageListener, boolean isHeic) throws Exception {
prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz,
- ImageFormat.JPEG, resultListener, MAX_READER_IMAGES, imageListener);
+ isHeic ? ImageFormat.HEIC : ImageFormat.JPEG, resultListener, MAX_READER_IMAGES,
+ imageListener);
}
/**
@@ -304,9 +305,9 @@
protected void prepareStillCaptureAndStartPreview(CaptureRequest.Builder previewRequest,
CaptureRequest.Builder stillRequest, Size previewSz, Size stillSz,
CaptureCallback resultListener, int maxNumImages,
- ImageReader.OnImageAvailableListener imageListener) throws Exception {
+ ImageReader.OnImageAvailableListener imageListener, boolean isHeic) throws Exception {
prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, stillSz,
- ImageFormat.JPEG, resultListener, maxNumImages, imageListener);
+ isHeic ? ImageFormat.HEIC : ImageFormat.JPEG, resultListener, maxNumImages, imageListener);
}
/**
@@ -573,11 +574,13 @@
* @param resultListener Capture result listener
* @param maxNumImages The max number of images set to the image reader
* @param imageListeners The single capture capture image listeners
+ * @param isHeic HEIC still capture if true, JPEG still capture if false
*/
protected ImageReader[] prepareStillCaptureAndStartPreview(
CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest,
Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener,
- int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners)
+ int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners,
+ boolean isHeic)
throws Exception {
if ((captureSizes == null) || (formats == null) || (imageListeners == null) &&
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index 4fd4b39..883d86b 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -1035,11 +1035,12 @@
ByteBuffer buffer = null;
// JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
- // Same goes for DEPTH_POINT_CLOUD and DEPTH_JPEG
+ // Same goes for DEPTH_POINT_CLOUD, RAW_PRIVATE, DEPTH_JPEG, and HEIC
if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD ||
- format == ImageFormat.RAW_PRIVATE || format == ImageFormat.DEPTH_JPEG) {
+ format == ImageFormat.RAW_PRIVATE || format == ImageFormat.DEPTH_JPEG ||
+ format == ImageFormat.HEIC) {
buffer = planes[0].getBuffer();
- assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
+ assertNotNull("Fail to get jpeg/depth/heic ByteBuffer", buffer);
data = new byte[buffer.remaining()];
buffer.get(data);
buffer.rewind();
@@ -1122,6 +1123,7 @@
case ImageFormat.DEPTH_POINT_CLOUD:
case ImageFormat.DEPTH_JPEG:
case ImageFormat.Y8:
+ case ImageFormat.HEIC:
assertEquals("JPEG/RAW/depth/Y8 Images should have one plane", 1, planes.length);
break;
default:
@@ -1364,6 +1366,11 @@
return getSortedSizesForFormat(cameraId, cameraManager, ImageFormat.JPEG, bound);
}
+ static public List<Size> getSupportedHeicSizes(String cameraId,
+ CameraManager cameraManager, Size bound) throws CameraAccessException {
+ return getSortedSizesForFormat(cameraId, cameraManager, ImageFormat.HEIC, bound);
+ }
+
static public Size getMinPreviewSize(String cameraId, CameraManager cameraManager)
throws CameraAccessException {
List<Size> sizes = getSupportedPreviewSizes(cameraId, cameraManager, null);
@@ -1551,6 +1558,9 @@
case ImageFormat.Y8:
validateY8Data(data, width, height, format, image.getTimestamp(), filePath);
break;
+ case ImageFormat.HEIC:
+ validateHeicData(data, width, height, filePath);
+ break;
default:
throw new UnsupportedOperationException("Unsupported format for validation: "
+ format);
@@ -1733,6 +1743,26 @@
}
+ private static void validateHeicData(byte[] heicData, int width, int height, String filePath) {
+ BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
+ // DecodeBound mode: only parse the frame header to get width/height.
+ // it doesn't decode the pixel.
+ bmpOptions.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(heicData, 0, heicData.length, bmpOptions);
+ assertEquals(width, bmpOptions.outWidth);
+ assertEquals(height, bmpOptions.outHeight);
+
+ // Pixel decoding mode: decode whole image. check if the image data
+ // is decodable here.
+ assertNotNull("Decoding heic failed",
+ BitmapFactory.decodeByteArray(heicData, 0, heicData.length));
+ if (DEBUG && filePath != null) {
+ String fileName =
+ filePath + "/" + width + "x" + height + ".heic";
+ dumpFile(fileName, heicData);
+ }
+ }
+
public static <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
if (result == null) {
throw new IllegalArgumentException("Result must not be null");
@@ -2047,49 +2077,54 @@
* continue the test if the jpeg image captured has some serious failures.
* </p>
*
- * @param image The captured jpeg image
- * @param expectedSize Expected capture jpeg size
+ * @param image The captured JPEG/HEIC image
+ * @param expectedSize Expected capture JEPG/HEIC size
+ * @param format JPEG/HEIC image format
*/
- public static void basicValidateJpegImage(Image image, Size expectedSize) {
+ public static void basicValidateBlobImage(Image image, Size expectedSize, int format) {
Size imageSz = new Size(image.getWidth(), image.getHeight());
assertTrue(
String.format("Image size doesn't match (expected %s, actual %s) ",
expectedSize.toString(), imageSz.toString()), expectedSize.equals(imageSz));
- assertEquals("Image format should be JPEG", ImageFormat.JPEG, image.getFormat());
+ assertEquals("Image format should be " + ((format == ImageFormat.HEIC) ? "HEIC" : "JPEG"),
+ format, image.getFormat());
assertNotNull("Image plane shouldn't be null", image.getPlanes());
assertEquals("Image plane number should be 1", 1, image.getPlanes().length);
- // Jpeg decoding validate was done in ImageReaderTest, no need to duplicate the test here.
+ // Jpeg/Heic decoding validate was done in ImageReaderTest,
+ // no need to duplicate the test here.
}
/**
- * Verify the JPEG EXIF and JPEG related keys in a capture result are expected.
+ * Verify the EXIF and JPEG related keys in a capture result are expected.
* - Capture request get values are same as were set.
* - capture result's exif data is the same as was set by
* the capture request.
* - new tags in the result set by the camera service are
* present and semantically correct.
*
- * @param image The output JPEG image to verify.
+ * @param image The output JPEG/HEIC image to verify.
* @param captureResult The capture result to verify.
- * @param expectedSize The expected JPEG size.
+ * @param expectedSize The expected JPEG/HEIC size.
* @param expectedThumbnailSize The expected thumbnail size.
* @param expectedExifData The expected EXIF data
* @param staticInfo The static metadata for the camera device.
- * @param jpegFilename The filename to dump the jpeg to.
+ * @param blobFilename The filename to dump the jpeg/heic to.
* @param collector The camera error collector to collect errors.
+ * @param format JPEG/HEIC format
*/
public static void verifyJpegKeys(Image image, CaptureResult captureResult, Size expectedSize,
Size expectedThumbnailSize, ExifTestData expectedExifData, StaticMetadata staticInfo,
- CameraErrorCollector collector, String debugFileNameBase) throws Exception {
+ CameraErrorCollector collector, String debugFileNameBase, int format) throws Exception {
- basicValidateJpegImage(image, expectedSize);
+ basicValidateBlobImage(image, expectedSize, format);
- byte[] jpegBuffer = getDataFromImage(image);
+ byte[] blobBuffer = getDataFromImage(image);
// Have to dump into a file to be able to use ExifInterface
- String jpegFilename = debugFileNameBase + "/verifyJpegKeys.jpeg";
- dumpFile(jpegFilename, jpegBuffer);
- ExifInterface exif = new ExifInterface(jpegFilename);
+ String filePostfix = (format == ImageFormat.HEIC ? ".heic" : ".jpeg");
+ String blobFilename = debugFileNameBase + "/verifyJpegKeys" + filePostfix;
+ dumpFile(blobFilename, blobBuffer);
+ ExifInterface exif = new ExifInterface(blobFilename);
if (expectedThumbnailSize.equals(new Size(0,0))) {
collector.expectTrue("Jpeg shouldn't have thumbnail when thumbnail size is (0, 0)",
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 15701f1..6af6be5 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -1347,6 +1347,16 @@
}
/**
+ * Get supported heic output sizes and do the check.
+ *
+ * @return Empty size array if heic output is not supported
+ */
+ public Size[] getHeicOutputSizesChecked() {
+ return getAvailableSizesForFormatChecked(ImageFormat.HEIC,
+ StreamDirection.Output);
+ }
+
+ /**
* Used to determine the stream direction for various helpers that look up
* format or size information.
*/
@@ -2361,6 +2371,14 @@
}
/**
+ * Check if HEIC format is supported
+ */
+ public boolean isHeicSupported() {
+ int[] formats = getAvailableFormats(StaticMetadata.StreamDirection.Output);
+ return CameraTestUtils.contains(formats, ImageFormat.HEIC);
+ }
+
+ /**
* Check if the dynamic black level is supported.
*
* <p>
diff --git a/tests/contentcaptureservice/AndroidTest.xml b/tests/contentcaptureservice/AndroidTest.xml
index b3c8635..f8afb9a 100644
--- a/tests/contentcaptureservice/AndroidTest.xml
+++ b/tests/contentcaptureservice/AndroidTest.xml
@@ -15,7 +15,7 @@
-->
<configuration description="Config for ContentCapture CTS tests.">
<option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="component" value="contentcapture" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
index f8f8092..072c770 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
@@ -15,7 +15,7 @@
*/
package android.contentcaptureservice.cts;
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import android.app.Activity;
import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
index 7e6f6f2..afcc95e 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
@@ -16,19 +16,20 @@
package android.contentcaptureservice.cts;
import static android.contentcaptureservice.cts.Helper.GENERIC_TIMEOUT_MS;
+import static android.contentcaptureservice.cts.Helper.SYSTEM_SERVICE_NAME;
import static android.contentcaptureservice.cts.Helper.resetService;
+import static android.contentcaptureservice.cts.Helper.sContext;
import static android.contentcaptureservice.cts.Helper.setService;
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
import static android.provider.Settings.Secure.CONTENT_CAPTURE_ENABLED;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
import android.app.Application;
-import android.content.Context;
import android.content.Intent;
import android.contentcaptureservice.cts.CtsContentCaptureService.ServiceWatcher;
import android.contentcaptureservice.cts.common.ActivitiesWatcher;
import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
import android.contentcaptureservice.cts.common.Visitor;
-import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
@@ -60,14 +61,12 @@
private final String mTag = getClass().getSimpleName();
- protected static final Context sContext = InstrumentationRegistry.getTargetContext();
-
protected ActivitiesWatcher mActivitiesWatcher;
private final Class<A> mActivityClass;
private final RequiredServiceRule mRequiredServiceRule =
- new RequiredServiceRule("content_capture");
+ new RequiredServiceRule(SYSTEM_SERVICE_NAME);
private final ContentCaptureLoggingTestRule mLoggingRule = new ContentCaptureLoggingTestRule();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CanaryTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CanaryTest.java
new file mode 100644
index 0000000..56839e2
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CanaryTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Helper.RESOURCE_STRING_SERVICE_NAME;
+import static android.contentcaptureservice.cts.Helper.SYSTEM_SERVICE_NAME;
+import static android.contentcaptureservice.cts.Helper.getInternalString;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureManager;
+
+import com.android.compatibility.common.util.RequiredServiceRule;
+
+import org.junit.Test;
+
+/**
+ * No-op test used to make sure the other tests are not passing because the feature is disabled.
+ */
+public class CanaryTest {
+
+ private static final String TAG = CanaryTest.class.getSimpleName();
+
+ @Test
+ public void logHasService() {
+ final boolean hasService = RequiredServiceRule.hasService(SYSTEM_SERVICE_NAME);
+ Log.d(TAG, "has " + SYSTEM_SERVICE_NAME + ": " + hasService);
+ assumeTrue("device doesn't have service " + SYSTEM_SERVICE_NAME, hasService);
+ }
+
+ @Test
+ public void assertHasService() {
+ final String serviceName = getInternalString(RESOURCE_STRING_SERVICE_NAME);
+ final String enableSettings = DeviceConfig.getProperty(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+ final boolean hasService = RequiredServiceRule.hasService(SYSTEM_SERVICE_NAME);
+ Log.d(TAG, "Service resource: '" + serviceName + "' Settings: '" + enableSettings
+ + "' Has '" + SYSTEM_SERVICE_NAME + "': " + hasService);
+
+ // We're only asserting when the OEM defines a service
+ assumeTrue("service resource (" + serviceName + ")is not defined",
+ !TextUtils.isEmpty(serviceName));
+ assertWithMessage("Should be enabled when resource '%s' is not empty (settings='%s')",
+ serviceName, enableSettings).that(hasService).isTrue();
+ }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
index 8dbda23..25928cd 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -29,6 +29,7 @@
import static android.contentcaptureservice.cts.Assertions.assertViewsDisappeared;
import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
import static android.contentcaptureservice.cts.Helper.newImportantView;
+import static android.contentcaptureservice.cts.Helper.sContext;
import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.RESUMED;
@@ -44,6 +45,7 @@
import android.net.Uri;
import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
import android.view.View;
@@ -57,10 +59,10 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.Arrays;
@@ -108,7 +110,6 @@
activity.assertDefaultEvents(session);
}
- @Ignore("not implemented yet, pending on b/123658889")
@Test
public void testGetContentCapture_disabledWhenNoService() throws Exception {
@@ -922,6 +923,28 @@
* - etc
*/
+ private enum DisabledReason {
+ BY_API,
+ BY_SETTINGS,
+ BY_DEVICE_CONFIG
+ }
+
+ private void setFeatureEnabled(@NonNull ContentCaptureManager mgr,
+ @NonNull DisabledReason reason, boolean enabled) {
+ switch (reason) {
+ case BY_API:
+ mgr.setContentCaptureFeatureEnabled(enabled);
+ break;
+ case BY_SETTINGS:
+ setFeatureEnabled(Boolean.toString(enabled));
+ break;
+ case BY_DEVICE_CONFIG:
+ setFeatureEnabledByDeviceConfig(Boolean.toString(enabled));
+ break;
+ default:
+ throw new IllegalArgumentException("invalid reason: " + reason);
+ }
+ }
@Test
public void testIsContentCaptureFeatureEnabled_notService() throws Exception {
final ContentCaptureManager mgr = getContentCaptureManagerHack();
@@ -930,21 +953,18 @@
@Test
public void testSetContentCaptureFeatureEnabled_disabledBySettings() throws Exception {
- setContentCaptureFeatureEnabledTest_disabled(/* bySettings= */ true);
+ setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_SETTINGS);
}
- private void setContentCaptureFeatureEnabledTest_disabled(boolean bySettings) throws Exception {
+ private void setContentCaptureFeatureEnabledTest_disabled(@NonNull DisabledReason reason)
+ throws Exception {
final ContentCaptureManager mgr = getContentCaptureManagerHack();
final CtsContentCaptureService service = enableService();
assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
final DisconnectListener disconnectedListener = service.setOnDisconnectListener();
- if (bySettings) {
- setFeatureEnabled("false");
- } else {
- mgr.setContentCaptureFeatureEnabled(false);
- }
+ setFeatureEnabled(mgr, reason, /* enabled= */ false);
disconnectedListener.waitForOnDisconnected();
assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse();
@@ -963,22 +983,18 @@
@Test
public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledBySettings()
throws Exception {
- setContentCaptureFeatureEnabledTest_disabledThenReEnabled(/* bySettings= */ true);
+ setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_SETTINGS);
}
- private void setContentCaptureFeatureEnabledTest_disabledThenReEnabled(boolean bySettings)
- throws Exception {
+ private void setContentCaptureFeatureEnabledTest_disabledThenReEnabled(
+ @NonNull DisabledReason reason) throws Exception {
final ContentCaptureManager mgr = getContentCaptureManagerHack();
final CtsContentCaptureService service1 = enableService();
assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
final DisconnectListener disconnectedListener = service1.setOnDisconnectListener();
- if (bySettings) {
- setFeatureEnabled("false");
- } else {
- mgr.setContentCaptureFeatureEnabled(false);
- }
+ setFeatureEnabled(mgr, reason, /* enabled= */ false);
disconnectedListener.waitForOnDisconnected();
assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse();
@@ -993,11 +1009,7 @@
// Re-enable feature
final ServiceWatcher reconnectionWatcher = CtsContentCaptureService.setServiceWatcher();
- if (bySettings) {
- setFeatureEnabled("true");
- } else {
- mgr.setContentCaptureFeatureEnabled(true);
- }
+ setFeatureEnabled(mgr, reason, /* enabled= */ true);
final CtsContentCaptureService service2 = reconnectionWatcher.waitOnCreate();
assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
@@ -1023,13 +1035,30 @@
@Test
public void testSetContentCaptureFeatureEnabled_disabledByApi() throws Exception {
- setContentCaptureFeatureEnabledTest_disabled(/* bySettings= */ false);
+ setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_API);
}
@Test
public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByApi()
throws Exception {
- setContentCaptureFeatureEnabledTest_disabledThenReEnabled(/* bySettings= */ false);
+ setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_API);
+ }
+
+ @Test
+ public void testSetContentCaptureFeatureEnabled_disabledByDeviceConfig() throws Exception {
+ setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_DEVICE_CONFIG);
+ // Reset service, otherwise it will reconnect when the deviceConfig value is reset
+ // on cleanup, which will cause the test to fail
+ Helper.resetService();
+ }
+
+ @Test
+ public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByDeviceConfig()
+ throws Exception {
+ setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_DEVICE_CONFIG);
+ // Reset service, otherwise it will reconnect when the deviceConfig value is reset
+ // on cleanup, which will cause the test to fail
+ Helper.resetService();
}
// TODO(b/123406031): add tests that mix feature_enabled with user_restriction_enabled (and
@@ -1086,4 +1115,34 @@
return mgr;
}
+
+ // TODO(b/124006095): should use a @Rule instead
+ private String mEnabledBefore;
+ @Before
+ public void saveDeviceConfig() {
+ mEnabledBefore = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+ Log.d(TAG, "@Before saveDeviceConfig(): " + mEnabledBefore);
+
+ setFeatureEnabledByDeviceConfig(null);
+
+ }
+ @After
+ // TODO(b/124006095): should use a @Rule instead
+ public void restoreDeviceConfig() {
+ Log.d(TAG, "@After restoreDeviceConfig(): " + mEnabledBefore);
+ setFeatureEnabledByDeviceConfig(mEnabledBefore);
+
+ }
+ // TODO(b/124006095): should use a DeviceConfigUtils instead
+ private void setFeatureEnabledByDeviceConfig(@Nullable String value) {
+ Log.d(TAG, "setFeatureEnabledByDeviceConfig(): " + value);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED,
+ value, /* makeDefault= */ false);
+
+ android.os.SystemClock.sleep(1000); // Wait a little bit since we're not using a listener
+ }
+
}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java
index c7b831a..f829c60 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureLoggingTestRule.java
@@ -18,7 +18,8 @@
import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
import static android.contentcaptureservice.cts.Helper.TAG;
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import android.util.Log;
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
index 30ba124..3b78e21 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
@@ -15,11 +15,13 @@
*/
package android.contentcaptureservice.cts;
-import static android.contentcaptureservice.cts.common.ShellHelper.runShellCommand;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -33,7 +35,7 @@
/**
* Helper for common funcionalities.
*/
-final class Helper {
+public final class Helper {
public static final String TAG = "ContentCaptureTest";
@@ -43,6 +45,12 @@
public static final long MY_EPOCH = SystemClock.uptimeMillis();
+ public static final String SYSTEM_SERVICE_NAME = "content_capture";
+
+ public static final String RESOURCE_STRING_SERVICE_NAME = "config_defaultContentCaptureService";
+
+ public static final Context sContext = InstrumentationRegistry.getTargetContext();
+
/**
* Awaits for a latch to be counted down.
*/
@@ -99,6 +107,15 @@
return child;
}
+ /**
+ * Gets a string from the Android resources.
+ */
+ public static String getInternalString(@NonNull String id) {
+ final Resources resources = sContext.getResources();
+ final int stringId = resources.getIdentifier(id, "string", "android");
+ return resources.getString(stringId);
+ }
+
private Helper() {
throw new UnsupportedOperationException("contain static methods only");
}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt
deleted file mode 100644
index 2cdbf75..0000000
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This package contains utilities that are not tied to Content Capture and might eventually move to
-a common CTS package.
\ No newline at end of file
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ShellHelper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ShellHelper.java
deleted file mode 100644
index a9b1481..0000000
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ShellHelper.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.contentcaptureservice.cts.common;
-
-import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-/**
- * Provides Shell-based utilities such as running a command.
- */
-public final class ShellHelper {
-
- private static final String TAG = "ShellHelper";
-
- /**
- * Runs a Shell command, returning a trimmed response.
- */
- @NonNull
- public static String runShellCommand(@NonNull String template, Object... args) {
- final String command = String.format(template, args);
- Log.d(TAG, "runShellCommand(): " + command);
- try {
- final String result = SystemUtil
- .runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
- return TextUtils.isEmpty(result) ? "" : result.trim();
- } catch (Exception e) {
- throw new RuntimeException("Command '" + command + "' failed: ", e);
- }
- }
-
- private ShellHelper() {
- throw new UnsupportedOperationException("contain static methods only");
- }
-}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureContextTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ContentCaptureContextTest.java
similarity index 98%
rename from tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureContextTest.java
rename to tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ContentCaptureContextTest.java
index c19f0f7..ed1ffce 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ContentCaptureContextTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ContentCaptureContextTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.contentcaptureservice.cts;
+package android.contentcaptureservice.cts.unit;
import static com.google.common.truth.Truth.assertThat;
@@ -34,8 +34,8 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@AppModeFull(reason = "unit test")
@RunWith(JUnit4.class)
-@AppModeFull // Unit test
public class ContentCaptureContextTest {
private static final Uri URI = Uri.parse("file:/dev/null");
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/UserDataRemovalRequestTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/UserDataRemovalRequestTest.java
new file mode 100644
index 0000000..93a15ec
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/UserDataRemovalRequestTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.contentcaptureservice.cts.unit;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.net.Uri;
+import android.platform.test.annotations.AppModeFull;
+import android.view.contentcapture.UserDataRemovalRequest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@AppModeFull(reason = "unit test")
+@RunWith(MockitoJUnitRunner.class)
+public class UserDataRemovalRequestTest {
+
+ @Mock
+ private final Uri mUri = Uri.parse("content://com.example/");
+
+ private UserDataRemovalRequest.Builder mBuilder = new UserDataRemovalRequest.Builder();
+
+ @Test
+ public void testBuilder_addUri_invalid() {
+ assertThrows(NullPointerException.class, () -> mBuilder.addUri(null, false));
+ }
+
+ @Test
+ public void testBuilder_addUri_valid() {
+ assertThat(mBuilder.addUri(mUri, false)).isNotNull();
+ assertThat(mBuilder.addUri(Uri.parse("content://com.example2"), true)).isNotNull();
+ }
+
+ @Test
+ public void testBuilder_addUriAfterForEverything() {
+ assertThat(mBuilder.forEverything()).isNotNull();
+ assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
+ }
+
+ @Test
+ public void testBuilder_forEverythingAfterAddingUri() {
+ assertThat(mBuilder.addUri(mUri, false)).isNotNull();
+ assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
+ }
+
+ @Test
+ public void testBuild_invalid() {
+ assertThrows(IllegalStateException.class, () -> mBuilder.build());
+ }
+
+ @Test
+ public void testBuild_valid() {
+ assertThat(new UserDataRemovalRequest.Builder().forEverything().build())
+ .isNotNull();
+ assertThat(new UserDataRemovalRequest.Builder().addUri(mUri, false).build())
+ .isNotNull();
+ }
+
+ @Test
+ public void testNoMoreInteractionsAfterBuild() {
+ assertThat(mBuilder.forEverything().build()).isNotNull();
+
+ assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
+ assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
+ assertThrows(IllegalStateException.class, () -> mBuilder.build());
+
+ }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ViewNodeTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ViewNodeTest.java
new file mode 100644
index 0000000..8d9cdeb
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/unit/ViewNodeTest.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.contentcaptureservice.cts.unit;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.platform.test.annotations.AppModeFull;
+import android.support.test.InstrumentationRegistry;
+import android.view.View;
+import android.view.ViewStructure.HtmlInfo;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ViewNode;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import android.widget.FrameLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Locale;
+
+@AppModeFull(reason = "unit test")
+@RunWith(MockitoJUnitRunner.class)
+public class ViewNodeTest {
+
+ private final Context mContext = InstrumentationRegistry.getTargetContext();
+
+ @Mock
+ private HtmlInfo mHtmlInfoMock;
+
+ @Test
+ public void testAutofillIdMethods_orphanView() {
+ View view = new View(mContext);
+ AutofillId initialId = new AutofillId(42);
+ view.setAutofillId(initialId);
+
+ ViewStructureImpl structure = new ViewStructureImpl(view);
+ ViewNode node = structure.getNode();
+
+ assertThat(node.getAutofillId()).isEqualTo(initialId);
+ assertThat(node.getParentAutofillId()).isNull();
+
+ AutofillId newId = new AutofillId(108);
+ structure.setAutofillId(newId);
+ assertThat(node.getAutofillId()).isEqualTo(newId);
+ assertThat(node.getParentAutofillId()).isNull();
+
+ structure.setAutofillId(new AutofillId(66), 6);
+ assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+ assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+ }
+
+ @Test
+ public void testAutofillIdMethods_parentedView() {
+ FrameLayout parent = new FrameLayout(mContext);
+ AutofillId initialParentId = new AutofillId(48);
+ parent.setAutofillId(initialParentId);
+
+ View child = new View(mContext);
+ AutofillId initialChildId = new AutofillId(42);
+ child.setAutofillId(initialChildId);
+
+ parent.addView(child);
+
+ ViewStructureImpl structure = new ViewStructureImpl(child);
+ ViewNode node = structure.getNode();
+
+ assertThat(node.getAutofillId()).isEqualTo(initialChildId);
+ assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+ AutofillId newChildId = new AutofillId(108);
+ structure.setAutofillId(newChildId);
+ assertThat(node.getAutofillId()).isEqualTo(newChildId);
+ assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+ AutofillId newParentId = new AutofillId(15162342);
+ parent.setAutofillId(newParentId);
+ assertThat(node.getAutofillId()).isEqualTo(newChildId);
+ assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+ structure.setAutofillId(new AutofillId(66), 6);
+ assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+ assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+ }
+
+ @Test
+ public void testAutofillIdMethods_explicitIdsConstructor() {
+ AutofillId initialParentId = new AutofillId(42);
+ ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108, 666);
+ ViewNode node = structure.getNode();
+
+ assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108, 666));
+ assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+ AutofillId newChildId = new AutofillId(108);
+ structure.setAutofillId(newChildId);
+ assertThat(node.getAutofillId()).isEqualTo(newChildId);
+ assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+ structure.setAutofillId(new AutofillId(66), 6);
+ assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+ assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+ }
+
+ @Test
+ public void testInvalidSetters() {
+ View view = new View(mContext);
+ AutofillId initialId = new AutofillId(42);
+ view.setAutofillId(initialId);
+
+ ViewStructureImpl structure = new ViewStructureImpl(view);
+ ViewNode node = structure.getNode();
+ assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
+
+ assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
+ assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+ assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
+ assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+ assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
+ assertThat(node.getTextIdEntry()).isNull();
+ }
+
+ @Test
+ public void testValidProperties_directly() {
+ ViewStructureImpl structure = newSimpleStructure();
+ assertSimpleStructure(structure);
+ assertSimpleNode(structure.getNode());
+ }
+
+ @Test
+ public void testValidProperties_throughParcel() {
+ ViewStructureImpl structure = newSimpleStructure();
+ final ViewNode node = structure.getNode();
+ assertSimpleNode(node); // sanity check
+
+ final ViewNode clone = cloneThroughParcel(node);
+ assertSimpleNode(clone);
+ }
+
+ @Test
+ public void testComplexText_directly() {
+ ViewStructureImpl structure = newStructureWithComplexText();
+ assertStructureWithComplexText(structure);
+ assertNodeWithComplexText(structure.getNode());
+ }
+
+ @Test
+ public void testComplexText_throughParcel() {
+ ViewStructureImpl structure = newStructureWithComplexText();
+ final ViewNode node = structure.getNode();
+ assertNodeWithComplexText(node); // sanity check
+
+ ViewNode clone = cloneThroughParcel(node);
+ assertNodeWithComplexText(clone);
+ }
+
+ @Test
+ public void testVisibility() {
+ // Visibility is a special case becase it use flag masks, so we want to make sure it works
+ // fine
+ View view = new View(mContext);
+ ViewStructureImpl structure = new ViewStructureImpl(view);
+ ViewNode node = structure.getNode();
+
+ structure.setVisibility(View.VISIBLE);
+ assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+ structure.setVisibility(View.GONE);
+ assertThat(node.getVisibility()).isEqualTo(View.GONE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+
+ structure.setVisibility(View.VISIBLE);
+ assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+ structure.setVisibility(View.INVISIBLE);
+ assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
+
+ structure.setVisibility(View.INVISIBLE | View.GONE);
+ assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+
+
+ final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
+ structure.setVisibility(View.VISIBLE);
+ structure.setVisibility(invalidValue); // should be ignored
+ assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+ structure.setVisibility(View.GONE | invalidValue);
+ assertThat(node.getVisibility()).isEqualTo(View.GONE);
+ assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+ }
+
+ /**
+ * Creates a {@link ViewStructureImpl} that can be asserted through
+ * {@link #assertSimpleNode(ViewNode)}.
+ */
+ private ViewStructureImpl newSimpleStructure() {
+ View view = new View(mContext);
+ view.setAutofillId(new AutofillId(42));
+
+ ViewStructureImpl structure = new ViewStructureImpl(view);
+
+ // Basic properties
+ structure.setText("Text is set!");
+ structure.setClassName("Classy!");
+ structure.setContentDescription("Described I am!");
+ structure.setVisibility(View.INVISIBLE);
+
+ // Autofill properties
+ structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+ structure.setAutofillHints(new String[] { "Auto", "Man" });
+ structure.setAutofillOptions(new String[] { "Maybe" });
+ structure.setAutofillValue(AutofillValue.forText("Malkovich"));
+
+ // Extra text properties
+ structure.setMinTextEms(6);
+ structure.setMaxTextLength(66);
+ structure.setMaxTextEms(666);
+ structure.setInputType(42);
+ structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
+ structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
+
+ // Resource id
+ structure.setId(16, "package.name", "type.name", "entry.name");
+
+ // Dimensions
+ structure.setDimens(4, 8, 15, 16, 23, 42);
+
+ // Boolean properties
+ structure.setAssistBlocked(true);
+ structure.setEnabled(true);
+ structure.setClickable(true);
+ structure.setLongClickable(true);
+ structure.setContextClickable(true);
+ structure.setFocusable(true);
+ structure.setFocused(true);
+ structure.setAccessibilityFocused(true);
+ structure.setChecked(true);
+ structure.setActivated(true);
+ structure.setOpaque(true);
+
+ // Bundle
+ assertThat(structure.hasExtras()).isFalse();
+ final Bundle bundle = structure.getExtras();
+ assertThat(bundle).isNotNull();
+ bundle.putString("Marlon", "Bundle");
+ assertThat(structure.hasExtras()).isTrue();
+ return structure;
+ }
+
+ /**
+ * Asserts the properties of a {@link ViewNode} that was created by
+ * {@link #newSimpleStructure()}.
+ */
+ private void assertSimpleNode(ViewNode node) {
+
+ // Basic properties
+ assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
+ assertThat(node.getParentAutofillId()).isNull();
+ assertThat(node.getText()).isEqualTo("Text is set!");
+ assertThat(node.getClassName()).isEqualTo("Classy!");
+ assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
+ assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+
+ // Autofill properties
+ assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
+ assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
+ assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
+ assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
+
+ // Extra text properties
+ assertThat(node.getMinTextEms()).isEqualTo(6);
+ assertThat(node.getMaxTextLength()).isEqualTo(66);
+ assertThat(node.getMaxTextEms()).isEqualTo(666);
+ assertThat(node.getInputType()).isEqualTo(42);
+ assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
+ assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
+
+ // Resource id
+ assertThat(node.getId()).isEqualTo(16);
+ assertThat(node.getIdPackage()).isEqualTo("package.name");
+ assertThat(node.getIdType()).isEqualTo("type.name");
+ assertThat(node.getIdEntry()).isEqualTo("entry.name");
+
+ // Dimensions
+ assertThat(node.getLeft()).isEqualTo(4);
+ assertThat(node.getTop()).isEqualTo(8);
+ assertThat(node.getScrollX()).isEqualTo(15);
+ assertThat(node.getScrollY()).isEqualTo(16);
+ assertThat(node.getWidth()).isEqualTo(23);
+ assertThat(node.getHeight()).isEqualTo(42);
+
+ // Boolean properties
+ assertThat(node.isAssistBlocked()).isTrue();
+ assertThat(node.isEnabled()).isTrue();
+ assertThat(node.isClickable()).isTrue();
+ assertThat(node.isLongClickable()).isTrue();
+ assertThat(node.isContextClickable()).isTrue();
+ assertThat(node.isFocusable()).isTrue();
+ assertThat(node.isFocused()).isTrue();
+ assertThat(node.isAccessibilityFocused()).isTrue();
+ assertThat(node.isChecked()).isTrue();
+ assertThat(node.isActivated()).isTrue();
+ assertThat(node.isOpaque()).isTrue();
+
+ // Bundle
+ final Bundle bundle = node.getExtras();
+ assertThat(bundle).isNotNull();
+ assertThat(bundle.size()).isEqualTo(1);
+ assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+ }
+
+ /**
+ * Asserts the properties of a {@link ViewStructureImpl} that was created by
+ * {@link #newSimpleStructure()}.
+ */
+ private void assertSimpleStructure(ViewStructureImpl structure) {
+ assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
+ assertThat(structure.getText()).isEqualTo("Text is set!");
+
+ // Bundle
+ final Bundle bundle = structure.getExtras();
+ assertThat(bundle.size()).isEqualTo(1);
+ assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+ }
+
+ /**
+ * Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
+ * can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
+ */
+ private ViewStructureImpl newStructureWithComplexText() {
+ View view = new View(mContext);
+ ViewStructureImpl structure = new ViewStructureImpl(view);
+ structure.setText("IGNORE ME!");
+ structure.setText("Now we're talking!", 4, 8);
+ structure.setHint("Soylent Green is SPOILER ALERT");
+ structure.setTextStyle(15.0f, 16, 23, 42);
+ structure.setTextLines(new int[] {4, 8, 15} , new int[] {16, 23, 42});
+ return structure;
+ }
+
+ /**
+ * Asserts the properties of a {@link ViewNode} that was created by
+ * {@link #newStructureWithComplexText()}.
+ */
+ private void assertNodeWithComplexText(ViewNode node) {
+ assertThat(node.getText()).isEqualTo("Now we're talking!");
+ assertThat(node.getTextSelectionStart()).isEqualTo(4);
+ assertThat(node.getTextSelectionEnd()).isEqualTo(8);
+ assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+ assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
+ assertThat(node.getTextColor()).isEqualTo(16);
+ assertThat(node.getTextBackgroundColor()).isEqualTo(23);
+ assertThat(node.getTextStyle()).isEqualTo(42);
+ assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
+ assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
+ }
+
+ /**
+ * Asserts the properties of a {@link ViewStructureImpl} that was created by
+ * {@link #newStructureWithComplexText()}.
+ */
+ private void assertStructureWithComplexText(ViewStructureImpl structure) {
+ assertThat(structure.getText()).isEqualTo("Now we're talking!");
+ assertThat(structure.getTextSelectionStart()).isEqualTo(4);
+ assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
+ assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+ }
+
+ private ViewNode cloneThroughParcel(ViewNode node) {
+ Parcel parcel = Parcel.obtain();
+
+ try {
+ // Write to parcel
+ parcel.setDataPosition(0); // Sanity / paranoid check
+ ViewNode.writeToParcel(parcel, node, 0);
+
+ // Read from parcel
+ parcel.setDataPosition(0);
+ ViewNode clone = ViewNode.readFromParcel(parcel);
+ assertThat(clone).isNotNull();
+ return clone;
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/tests/fragment/Android.bp b/tests/fragment/Android.bp
new file mode 100644
index 0000000..64a4486
--- /dev/null
+++ b/tests/fragment/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "CtsFragmentTestCases",
+ defaults: ["cts_defaults"],
+
+ dex_preopt: {
+ enabled: false,
+ },
+
+ optimize: {
+ enabled: false,
+ },
+
+ static_libs: [
+ "android-support-test",
+ "mockito-target-minus-junit4",
+ "android-common",
+ "compatibility-device-util",
+ "ctstestrunner",
+ ],
+ libs: ["android.test.base.stubs"],
+
+ srcs: ["src/**/*.java"],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ "cts_instant",
+ ],
+
+ sdk_version: "test_current",
+}
diff --git a/tests/fragment/Android.mk b/tests/fragment/Android.mk
deleted file mode 100644
index 94a4d91..0000000
--- a/tests/fragment/Android.mk
+++ /dev/null
@@ -1,49 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsFragmentTestCases
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
- android-support-test \
- mockito-target-minus-junit4 \
- android-common \
- compatibility-device-util \
- ctstestrunner
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-#LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/fragment/TEST_MAPPING b/tests/fragment/TEST_MAPPING
new file mode 100644
index 0000000..a5be057
--- /dev/null
+++ b/tests/fragment/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsFragmentTestCases"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/fragment/sdk26/Android.bp b/tests/fragment/sdk26/Android.bp
new file mode 100644
index 0000000..303c3cd
--- /dev/null
+++ b/tests/fragment/sdk26/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "CtsFragmentTestCasesSdk26",
+ defaults: ["cts_defaults"],
+
+ optimize: {
+ enabled: false,
+ },
+
+ static_libs: ["android-support-test"],
+
+ srcs: ["src/**/*.java"],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ "cts_instant",
+ ],
+
+ sdk_version: "26",
+}
diff --git a/tests/fragment/sdk26/Android.mk b/tests/fragment/sdk26/Android.mk
deleted file mode 100644
index 5947137..0000000
--- a/tests/fragment/sdk26/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsFragmentTestCasesSdk26
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-LOCAL_SDK_VERSION := 26
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/fragment/sdk26/TEST_MAPPING b/tests/fragment/sdk26/TEST_MAPPING
new file mode 100644
index 0000000..28bdfed
--- /dev/null
+++ b/tests/fragment/sdk26/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsFragmentTestCasesSdk26"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml b/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml
index 04cace4..5085834 100644
--- a/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml
+++ b/tests/framework/base/activitymanager/appPrereleaseSdk/fake-framework/res/values/values.xml
@@ -37,6 +37,9 @@
<public type="attr" name="targetSdkVersion" id="0x01010270" />
<attr name="targetSdkVersion" format="integer|string" />
+ <public type="attr" name="extractNativeLibs" id="0x10104ea" />
+ <attr name="extractNativeLibs" format="boolean" />
+
<public type="attr" name="compileSdkVersion" id="0x01010572" />
<attr name="compileSdkVersion" format="integer" />
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
index 328d27e..c568d19 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
@@ -148,7 +148,8 @@
* Blocking call that will wait for activities to reach expected states with timeout.
*/
@SafeVarargs
- final void waitAndAssertActivityStates(Pair<Activity, ActivityCallback>... activityCallbacks) {
+ final void waitAndAssertActivityStates(
+ Pair<Class<? extends Activity>, ActivityCallback>... activityCallbacks) {
log("Start waitAndAssertActivityCallbacks");
mLifecycleTracker.waitAndAssertActivityStates(activityCallbacks);
}
@@ -181,15 +182,16 @@
return mLifecycleLog;
}
- static Pair<Activity, ActivityCallback> state(Activity activity, ActivityCallback stage) {
- return new Pair<>(activity, stage);
+ static Pair<Class<? extends Activity>, ActivityCallback> state(Activity activity,
+ ActivityCallback stage) {
+ return new Pair<>(activity.getClass(), stage);
}
/**
* Returns a pair of the activity and the state it should be in based on the configuration of
* occludingActivity.
*/
- static Pair<Activity, ActivityCallback> occludedActivityState(
+ static Pair<Class<? extends Activity>, ActivityCallback> occludedActivityState(
Activity activity, Activity occludingActivity) {
return occludedActivityState(activity, isTranslucent(occludingActivity));
}
@@ -198,11 +200,11 @@
* Returns a pair of the activity and the state it should be in based on
* occludingActivityIsTranslucent.
*/
- static Pair<Activity, ActivityCallback> occludedActivityState(
+ static Pair<Class<? extends Activity>, ActivityCallback> occludedActivityState(
Activity activity, boolean occludingActivityIsTranslucent) {
// Activities behind a translucent activity should be in the paused state since they are
// still visible. Otherwise, they should be in the stopped state.
- return new Pair<>(activity, occludedActivityState(occludingActivityIsTranslucent));
+ return state(activity, occludedActivityState(occludingActivityIsTranslucent));
}
static ActivityCallback occludedActivityState(boolean occludingActivityIsTranslucent) {
@@ -352,4 +354,15 @@
static ComponentName getComponentName(Class<? extends Activity> activity) {
return new ComponentName(getInstrumentation().getContext(), activity);
}
+
+ void moveTaskToPrimarySplitScreenAndVerify(Activity activity) {
+ getLifecycleLog().clear();
+
+ moveTaskToPrimarySplitScreen(activity.getTaskId());
+
+ final Class<? extends Activity> activityClass = activity.getClass();
+ waitAndAssertActivityTransitions(activityClass,
+ LifecycleVerifier.getSplitScreenTransitionSequence(activityClass),
+ "enterSplitScreen");
+ }
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java
index 044f5bc..bab51ac 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleFreeformTests.java
@@ -77,10 +77,8 @@
// Wait and assert resume
waitAndAssertActivityState(getComponentName(FirstActivity.class), STATE_RESUMED,
"Activity should be resumed after launch");
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
}
@Test
@@ -112,14 +110,10 @@
waitAndAssertActivityState(getComponentName(ThirdActivity.class), STATE_RESUMED, message);
// Assert lifecycle
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
}
@Test
@@ -152,12 +146,9 @@
// Assert lifecycle
LifecycleVerifier.assertLaunchAndStopSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
// Finish the activity that was occluding the first one
getLifecycleLog().clear();
@@ -213,12 +204,9 @@
// Assert lifecycle
LifecycleVerifier.assertLaunchAndPauseSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
// Finish the activity that was occluding the first one
getLifecycleLog().clear();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java
index 00138cf..ab99a58 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleKeyguardTests.java
@@ -91,7 +91,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Enter split screen
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// Launch second activity to side
final Activity secondActivity = mSecondActivityTestRule.launchActivity(
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java
index 0fbc0ca..8a77fcb 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecyclePipTests.java
@@ -154,8 +154,7 @@
// Wait and verify the sequence
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
"launchBelowPip");
}
@@ -225,17 +224,10 @@
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK));
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
// Enter split screen
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
-
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
- Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START,
- ON_RESUME, ON_PAUSE), "moveToSplitScreen");
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// TODO(b/123013403): will fail with callback tracking enabled - delivers extra
// MULTI_WINDOW_MODE_CHANGED
LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
@@ -248,8 +240,7 @@
// Wait for activities to resume and verify lifecycle
waitAndAssertActivityStates(state(secondActivity, ON_RESUME));
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
Arrays.asList(ON_RESUME), "launchToSide");
LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
@@ -263,7 +254,7 @@
mFirstActivityTestRule.launchActivity(new Intent());
// Enter split screen
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// Launch second activity to side
final Activity secondActivity = mSecondActivityTestRule.launchActivity(
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java
index 7707f1b..4950aa6 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleSplitScreenTests.java
@@ -50,6 +50,7 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -84,7 +85,7 @@
state(firstActivity, ON_STOP));
// Enter split screen
- moveTaskToPrimarySplitScreen(secondActivity.getTaskId());
+ moveTaskToPrimarySplitScreenAndVerify(secondActivity);
// CLear logs so we can capture just the destroy sequence
getLifecycleLog().clear();
@@ -111,8 +112,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Enter split screen
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
final ComponentName firstActivityName = getComponentName(FirstActivity.class);
mAmWmState.computeState(firstActivityName);
@@ -142,7 +142,9 @@
waitAndAssertActivityStates(state(secondActivity, ON_RESUME),
state(firstActivity, ON_STOP));
- LifecycleVerifier.assertEmptySequence(ThirdActivity.class, getLifecycleLog(), "moveToSide");
+ LifecycleVerifier.assertSequenceMatchesOneOf(ThirdActivity.class, getLifecycleLog(),
+ Arrays.asList(new ArrayList<>(), LifecycleVerifier.getRelaunchSequence(ON_RESUME)),
+ "moveToSide");
LifecycleVerifier.assertRestartAndResumeSequence(SecondActivity.class, getLifecycleLog());
LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
Arrays.asList(ON_PAUSE, ON_STOP), "moveToSide");
@@ -156,8 +158,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Enter split screen
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
final ComponentName firstActivityName = getComponentName(FirstActivity.class);
mAmWmState.computeState(firstActivityName);
@@ -179,19 +180,15 @@
final Activity translucentActivity = mTranslucentActivityTestRule.launchActivity(
new Intent().setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK));
- waitAndAssertActivityStates(state(translucentActivity, ON_RESUME));
- // Second activity should stay resumed, because it's in a separate stack below the
- // translucent activity.
- LifecycleVerifier.assertEmptySequence(SecondActivity.class, getLifecycleLog(),
- "moveToSide");
+ waitAndAssertActivityStates(state(translucentActivity, ON_RESUME),
+ state(secondActivity, ON_PAUSE));
// Move translucent activity to side, it will be on top of the first now
getLifecycleLog().clear();
moveActivityToStack(getComponentName(TranslucentActivity.class), primarySplitStack);
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
- LifecycleVerifier.assertEmptySequence(SecondActivity.class, getLifecycleLog(),
- "moveToSide");
+ waitAndAssertActivityStates(state(firstActivity, ON_PAUSE),
+ state(secondActivity, ON_RESUME));
LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
Arrays.asList(ON_PAUSE), "moveToSide");
// Translucent activity can be either relaunched or preserved depending on whether the split
@@ -208,16 +205,7 @@
waitAndAssertActivityStates(state(callbackTrackingActivity, ON_TOP_POSITION_GAINED));
// Enter split screen, the activity will be relaunched.
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(callbackTrackingActivity.getTaskId());
- // Wait for multi-window mode change that will come after activity relaunch and resume.
- waitAndAssertActivityStates(state(callbackTrackingActivity, ON_PAUSE));
- final List<LifecycleLog.ActivityCallback> splitScreenMoveSequence = Arrays.asList(
- ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE,
- ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
- ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST, ON_PAUSE);
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- splitScreenMoveSequence, "moveToPrimarySplitScreen");
+ moveTaskToPrimarySplitScreenAndVerify(callbackTrackingActivity);
getLifecycleLog().clear();
// Launch second activity
@@ -268,12 +256,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Enter split screen
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(), Arrays.asList(
- ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME,
- ON_PAUSE), "enterSplitScreen");
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// Start an activity in separate task (will be placed in secondary stack)
final Activity newTaskActivity = mThirdActivityTestRule.launchActivity(
@@ -353,8 +336,7 @@
// Wait for the activity to resume
waitAndAssertActivityStates(state(testActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
// Enter split screen
getLifecycleLog().clear();
@@ -402,7 +384,7 @@
// Wait for the activity to resume
waitAndAssertActivityStates(state(testActivity, ON_TOP_POSITION_GAINED));
LifecycleVerifier.assertLaunchSequence(ConfigChangeHandlingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
// Enter split screen
getLifecycleLog().clear();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
index d20f1b3..f9b25bb 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
@@ -71,8 +71,7 @@
final Activity activity = mFirstActivityTestRule.launchActivity(new Intent());
waitAndAssertActivityStates(state(activity, ON_RESUME));
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog(),
- false /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
}
@Test
@@ -654,8 +653,7 @@
// Wait for the activity to resume
waitAndAssertActivityStates(state(singleTopActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
// Try to launch again
getLifecycleLog().clear();
@@ -680,8 +678,7 @@
// Wait for the activity to resume
waitAndAssertActivityStates(state(singleTopActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
// Launch something on top
final Intent newTaskIntent = new Intent();
@@ -724,8 +721,7 @@
// Wait for the activity to resume
waitAndAssertActivityStates(state(singleTopActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
// Launch translucent activity, which will make the first one paused.
mTranslucentActivityTestRule.launchActivity(new Intent());
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java
index df99ae8..0dd03be 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTopResumedStateTests.java
@@ -9,7 +9,6 @@
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_ACTIVITY_RESULT;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_CREATE;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_DESTROY;
-import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_NEW_INTENT;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_PAUSE;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_POST_CREATE;
@@ -59,8 +58,7 @@
final Activity activity = mCallbackTrackingActivityTestRule.launchActivity(new Intent());
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
}
@Test
@@ -73,7 +71,7 @@
mAmWmState.waitForActivityRemoved(getComponentName(CallbackTrackingActivity.class));
LifecycleVerifier.assertResumeToDestroySequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
}
@Test
@@ -88,7 +86,7 @@
LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class,
CallbackTrackingActivity.class, getLifecycleLog(),
- false /* launchingIsTranslucent */, true /* includingCallbacks */);
+ false /* launchingIsTranslucent */);
}
@Test
@@ -104,7 +102,7 @@
LifecycleVerifier.assertLaunchSequence(TranslucentCallbackTrackingActivity.class,
CallbackTrackingActivity.class, getLifecycleLog(),
- true /* launchingIsTranslucent */, true /* includingCallbacks */);
+ true /* launchingIsTranslucent */);
}
@Test
@@ -209,14 +207,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
// Enter split screen
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE,
- ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
- ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST, ON_PAUSE),
- "moveToDocked");
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
}
@Test
@@ -229,9 +220,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
// Enter split screen
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// Launch second activity to side
getLifecycleLog().clear();
@@ -245,8 +234,7 @@
LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
Arrays.asList(ON_RESUME), "unminimizeDockedStack");
// Second activity must be on top now
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
}
@Test
@@ -259,9 +247,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
// Enter split screen
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// Launch second activity to side
getLifecycleLog().clear();
@@ -396,7 +382,7 @@
waitAndAssertActivityStates(state(topActivity, ON_STOP));
LifecycleVerifier.assertResumeToStopSequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
}
@Test
@@ -409,9 +395,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
// Enter split screen
- getLifecycleLog().clear();
- moveTaskToPrimarySplitScreen(firstActivity.getTaskId());
- waitAndAssertActivityStates(state(firstActivity, ON_PAUSE));
+ moveTaskToPrimarySplitScreenAndVerify(firstActivity);
// Launch second activity to side
getLifecycleLog().clear();
@@ -480,7 +464,7 @@
new Intent());
waitAndAssertActivityStates(state(activity, ON_STOP));
LifecycleVerifier.assertLaunchAndStopSequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */, false /* onTop */);
+ getLifecycleLog(), false /* onTop */);
getLifecycleLog().clear();
}
@@ -488,7 +472,7 @@
// Lock screen removed - activity should be on top now
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
LifecycleVerifier.assertStopToResumeSequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
}
@Test
@@ -504,7 +488,7 @@
waitAndAssertActivityStates(state(activity, ON_STOP));
LifecycleVerifier.assertResumeToStopSequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
getLifecycleLog().clear();
}
@@ -512,7 +496,7 @@
// Lock screen removed - activity should be on top now
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
LifecycleVerifier.assertStopToResumeSequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
}
@Test
@@ -540,8 +524,7 @@
// Wait for something here, but don't expect anything to happen.
waitAndAssertActivityStates(state(showWhenLockedActivity, ON_DESTROY));
LifecycleVerifier.assertResumeToDestroySequence(
- ShowWhenLockedCallbackTrackingActivity.class, getLifecycleLog(),
- true /* includeCallbacks */);
+ ShowWhenLockedCallbackTrackingActivity.class, getLifecycleLog());
}
@Test
@@ -558,7 +541,7 @@
waitAndAssertTopResumedActivity(getComponentName(CallbackTrackingActivity.class),
DEFAULT_DISPLAY, "Activity launched on default display must be focused");
waitAndAssertActivityTransitions(CallbackTrackingActivity.class,
- LifecycleVerifier.getLaunchSequence(true /* includeCallbacks */), "launch");
+ LifecycleVerifier.getLaunchSequence(CallbackTrackingActivity.class), "launch");
try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
// Create new simulated display
@@ -575,7 +558,7 @@
newDisplay.mId, "Activity launched on secondary display must be focused");
waitAndAssertActivityTransitions(SingleTopActivity.class,
- LifecycleVerifier.getLaunchSequence(true /* includeCallbacks */), "launch");
+ LifecycleVerifier.getLaunchSequence(SingleTopActivity.class), "launch");
LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED)),
@@ -586,7 +569,7 @@
// Secondary display was removed - activity will be moved to the default display
waitAndAssertActivityTransitions(SingleTopActivity.class,
- LifecycleVerifier.getResumeToDestroySequence(true /* includeCallbacks */),
+ LifecycleVerifier.getResumeToDestroySequence(SingleTopActivity.class),
"hostingDisplayRemoved");
waitAndAssertActivityTransitions(CallbackTrackingActivity.class,
Arrays.asList(ON_TOP_POSITION_GAINED, ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP),
@@ -734,7 +717,7 @@
waitAndAssertActivityStates(state(alwaysFocusableActivity, ON_DESTROY),
state(activity, ON_TOP_POSITION_GAINED), state(pipActivity, ON_PAUSE));
LifecycleVerifier.assertResumeToDestroySequence(AlwaysFocusablePipActivity.class,
- getLifecycleLog(), true /* includeCallbacks */);
+ getLifecycleLog());
LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
transition(AlwaysFocusablePipActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED)),
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java
index 25374e5..24eb301 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleTracker.java
@@ -40,7 +40,8 @@
mLifecycleLog = lifecycleLog;
}
- void waitAndAssertActivityStates(Pair<Activity, ActivityCallback>[] activityCallbacks) {
+ void waitAndAssertActivityStates(
+ Pair<Class<? extends Activity>, ActivityCallback>[] activityCallbacks) {
final boolean waitResult = waitForConditionWithTimeout(
() -> pendingCallbacks(activityCallbacks).isEmpty(), 5 * 1000);
@@ -68,19 +69,20 @@
}
/** Get a list of activity states that were not reached yet. */
- private List<Pair<Activity, ActivityCallback>> pendingCallbacks(Pair<Activity,
- ActivityCallback>[] activityCallbacks) {
- final List<Pair<Activity, ActivityCallback>> notReachedActivityCallbacks = new ArrayList<>();
+ private List<Pair<Class<? extends Activity>, ActivityCallback>> pendingCallbacks(
+ Pair<Class<? extends Activity>, ActivityCallback>[] activityCallbacks) {
+ final List<Pair<Class<? extends Activity>, ActivityCallback>> notReachedActivityCallbacks =
+ new ArrayList<>();
- for (Pair<Activity, ActivityCallback> activityCallback : activityCallbacks) {
- final Activity activity = activityCallback.first;
+ for (Pair<Class<? extends Activity>, ActivityCallback> callbackPair : activityCallbacks) {
+ final Class<? extends Activity> activityClass = callbackPair.first;
final List<ActivityCallback> transitionList =
- mLifecycleLog.getActivityLog(activity.getClass());
+ mLifecycleLog.getActivityLog(activityClass);
if (transitionList.isEmpty()
- || transitionList.get(transitionList.size() - 1) != activityCallback.second) {
+ || transitionList.get(transitionList.size() - 1) != callbackPair.second) {
// The activity either hasn't got any state transitions yet or the current state is
// not the one we expect.
- notReachedActivityCallbacks.add(activityCallback);
+ notReachedActivityCallbacks.add(callbackPair);
}
}
return notReachedActivityCallbacks;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
index 1f35d1f..a289682 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
@@ -19,6 +19,7 @@
import static android.server.am.StateLogger.log;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_CREATE;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_DESTROY;
+import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_PAUSE;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_POST_CREATE;
import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_RESTART;
@@ -34,6 +35,7 @@
import static org.junit.Assert.fail;
import android.app.Activity;
+import android.server.am.lifecycle.ActivityLifecycleClientTestBase.CallbackTrackingActivity;
import android.server.am.lifecycle.LifecycleLog.ActivityCallback;
import android.util.Pair;
@@ -44,19 +46,22 @@
/** Util class that verifies correct activity state transition sequences. */
class LifecycleVerifier {
+ private static final Class CALLBACK_TRACKING_CLASS = CallbackTrackingActivity.class;
+
static void assertLaunchSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, boolean includeCallbacks) {
+ LifecycleLog lifecycleLog) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch");
- final List<ActivityCallback> expectedTransitions = getLaunchSequence(includeCallbacks);
+ final List<ActivityCallback> expectedTransitions = getLaunchSequence(activityClass);
assertEquals(errorMessage, expectedTransitions, observedTransitions);
}
- public static List<ActivityCallback> getLaunchSequence(boolean includeCallbacks) {
- return includeCallbacks
+ public static List<ActivityCallback> getLaunchSequence(
+ Class<? extends Activity> activityClass) {
+ return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass)
? Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME,
ON_TOP_POSITION_GAINED)
: Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME);
@@ -65,13 +70,20 @@
static void assertLaunchSequence(Class<? extends Activity> launchingActivity,
Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog,
boolean launchingIsTranslucent) {
- assertLaunchSequence(launchingActivity, existingActivity, lifecycleLog,
- launchingIsTranslucent, false /* includingCallbacks */);
- }
+ final boolean includingCallbacks;
+ if (CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity)
+ && CALLBACK_TRACKING_CLASS.isAssignableFrom(existingActivity)) {
+ includingCallbacks = true;
+ } else if (!CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity)
+ && !CALLBACK_TRACKING_CLASS.isAssignableFrom(existingActivity)) {
+ includingCallbacks = false;
+ } else {
+ throw new IllegalArgumentException("Mixed types of callback tracking not supported. "
+ + "Both activities must support or not support callback tracking "
+ + "simultaneously");
+ }
- static void assertLaunchSequence(Class<? extends Activity> launchingActivity,
- Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog,
- boolean launchingIsTranslucent, boolean includingCallbacks) {
+
final List<Pair<String, ActivityCallback>> observedTransitions = lifecycleLog.getLog();
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(launchingActivity, "launch");
@@ -102,17 +114,19 @@
static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass,
LifecycleLog lifecycleLog) {
- assertLaunchAndStopSequence(activityClass, lifecycleLog, false /* includeCallbacks */,
+ assertLaunchAndStopSequence(activityClass, lifecycleLog,
false /* onTop */);
}
static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, boolean includeCallbacks, boolean onTop) {
+ LifecycleLog lifecycleLog, boolean onTop) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch and stop");
+ final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
+
final List<ActivityCallback> expectedTransitions = new ArrayList<>();
expectedTransitions.addAll(Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START));
if (includeCallbacks) {
@@ -151,7 +165,7 @@
}
static void assertRestartAndResumeSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ LifecycleLog lifecycleLog) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
@@ -163,7 +177,7 @@
}
static void assertRecreateAndResumeSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ LifecycleLog lifecycleLog) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
@@ -188,38 +202,30 @@
static void assertResumeToDestroySequence(Class<? extends Activity> activityClass,
LifecycleLog lifecycleLog) {
- assertResumeToDestroySequence(activityClass, lifecycleLog, false /* includeCallbacks */);
- }
-
- static void assertResumeToDestroySequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, boolean includeCallbacks) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch and destroy");
final List<ActivityCallback> expectedTransitions =
- getResumeToDestroySequence(includeCallbacks);
+ getResumeToDestroySequence(activityClass);
assertEquals(errorMessage, expectedTransitions, observedTransitions);
}
- static List<ActivityCallback> getResumeToDestroySequence(boolean includeCallbacks) {
- return includeCallbacks
+ static List<ActivityCallback> getResumeToDestroySequence(
+ Class<? extends Activity> activityClass) {
+ return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass)
? Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY)
: Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY);
}
static void assertResumeToStopSequence(Class<? extends Activity> activityClass,
LifecycleLog lifecycleLog) {
- assertResumeToStopSequence(activityClass, lifecycleLog, false /* includeCallbacks */);
- }
-
- static void assertResumeToStopSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, boolean includeCallbacks) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "resumed to stopped");
+ final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
final List<ActivityCallback> expectedTransitions = new ArrayList<>();
if (includeCallbacks) {
@@ -232,11 +238,12 @@
}
static void assertStopToResumeSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, boolean includeCallbacks) {
+ LifecycleLog lifecycleLog) {
final List<ActivityCallback> observedTransitions =
lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "stopped to resumed");
+ final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
final List<ActivityCallback> expectedTransitions = new ArrayList<>(
Arrays.asList(ON_RESTART, ON_START, ON_RESUME));
@@ -249,6 +256,11 @@
static void assertRelaunchSequence(Class<? extends Activity> activityClass,
LifecycleLog lifecycleLog, ActivityCallback startState) {
+ final List<ActivityCallback> expectedTransitions = getRelaunchSequence(startState);
+ assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch");
+ }
+
+ static List<ActivityCallback> getRelaunchSequence(ActivityCallback startState) {
final List<ActivityCallback> expectedTransitions;
if (startState == ON_PAUSE) {
expectedTransitions = Arrays.asList(
@@ -267,7 +279,17 @@
} else {
throw new IllegalArgumentException("Start state not supported: " + startState);
}
- assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch");
+ return expectedTransitions;
+ }
+
+ static List<ActivityCallback> getSplitScreenTransitionSequence(
+ Class<? extends Activity> activityClass) {
+ return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass)
+ ? Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE,
+ ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
+ ON_TOP_POSITION_LOST, ON_PAUSE, ON_MULTI_WINDOW_MODE_CHANGED)
+ : Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START,
+ ON_RESUME, ON_PAUSE);
}
static void assertSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog,
diff --git a/tests/providerui/AndroidTest.xml b/tests/providerui/AndroidTest.xml
index 6a123f6..9ef1d6c 100644
--- a/tests/providerui/AndroidTest.xml
+++ b/tests/providerui/AndroidTest.xml
@@ -16,7 +16,9 @@
<configuration description="Config for CTS Provider UI test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <!-- Instant apps cannot access external storage -->
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsProviderUiTestCases.apk" />
diff --git a/tests/signature/api-check/build_signature_apk.mk b/tests/signature/api-check/build_signature_apk.mk
index b883d6a..23457d3 100644
--- a/tests/signature/api-check/build_signature_apk.mk
+++ b/tests/signature/api-check/build_signature_apk.mk
@@ -74,6 +74,8 @@
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_CTS_PACKAGE)
LOCAL_SIGNATURE_API_FILES :=
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
index 7423448..003eb7f 100644
--- a/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch-debug-class/Android.mk
@@ -27,4 +27,6 @@
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
index 9364286..5dca9c1 100644
--- a/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch-whitelist/Android.mk
@@ -27,4 +27,6 @@
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
index 2274762..ab0eef9 100644
--- a/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch-wildcard/Android.mk
@@ -27,4 +27,6 @@
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
index 655eb1c..ef2d35ac 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -205,18 +204,23 @@
@Test
public void testNullObjectAnimator() throws Throwable {
- Object object = mActivity.view.newBall;
- final ObjectAnimator animator = ObjectAnimator.ofFloat(object, "y", 0, 100);
+ class AnimTarget {
+ public float y = 0f;
+ public void setY(float y) {
+ this.y = y;
+ }
+
+ public float getY() {
+ return y;
+ }
+ }
+ final ObjectAnimator animator = ObjectAnimator.ofFloat(new AnimTarget(), "y", 0, 100);
MyListener listener = new MyListener();
animator.addListener(listener);
- mActivity.view.newBall.setY(0);
- startAnimation(animator);
- int sleepCount = 0;
- while (mActivity.view.newBall.getY() == 0 && sleepCount++ < 50) {
- SystemClock.sleep(1);
- }
- assertNotSame(0, mActivity.view.newBall.getY());
- mActivityRule.runOnUiThread(() -> animator.setTarget(null));
+ mActivityRule.runOnUiThread(() -> {
+ animator.start();
+ animator.setTarget(null);
+ });
assertTrue(listener.mCancel);
}
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index e7d939f..427237c 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -32,8 +32,10 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.SystemClock;
@@ -480,43 +482,76 @@
@Test
public void testGetAnimatedFraction() throws Throwable {
- ValueAnimator objAnimator = getAnimator();
- objAnimator.setRepeatCount(0);
- startAnimation(objAnimator);
- assertNotNull(objAnimator);
- float[] fractions = getValue(objAnimator, 5, "getAnimatedFraction()", 100L, null);
- for (int j = 0; j < fractions.length - 1; j++) {
- assertTrue(fractions[j] >= 0.0);
- assertTrue(fractions[j] <= 1.0);
- assertTrue(errorMessage(fractions), fractions[j + 1] >= fractions[j]);
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ assertNotNull(animator);
+ animator.setDuration(200);
+ animator.addUpdateListener(new AnimatorUpdateListener() {
+ public float lastFraction = 0;
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float currentFraction = animation.getAnimatedFraction();
+ assertTrue(
+ "Last fraction = " + lastFraction + "current fraction = " + currentFraction,
+ animation.getAnimatedFraction() >= lastFraction);
+ lastFraction = currentFraction;
+ assertTrue(currentFraction <= 1f);
+ }
+ });
+ CountDownLatch latch = new CountDownLatch(1);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ latch.countDown();
+ }
+ });
+ mActivityRule.runOnUiThread(() -> {
+ animator.start();
+ });
+
+ latch.await(1000, TimeUnit.MILLISECONDS);
+
+ assertEquals(1.0f, animator.getAnimatedFraction(), EPSILON);
+ }
+
+ class TestInterpolator implements TimeInterpolator {
+
+ @Override
+ public float getInterpolation(float input) {
+ return input * input;
}
}
@Test
- public void testGetAnimatedValue() throws Throwable {
- ValueAnimator objAnimator = getAnimator();
- objAnimator.setRepeatCount(0);
- startAnimation(objAnimator);
- assertNotNull(objAnimator);
- float[] animatedValues = getValue(objAnimator, 5, "getAnimatedValue()", 100L, null);
+ public void testGetAnimatedValue() {
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ assertNotNull(animator);
+ TimeInterpolator myInterpolator = new TestInterpolator();
+ animator.setInterpolator(myInterpolator);
+ int sliceNum = 10;
+ for (int i = 0; i <= sliceNum; i++) {
+ float fraction = i / (float) sliceNum;
+ animator.setCurrentFraction(fraction);
+ assertEquals(myInterpolator.getInterpolation(fraction),
+ (float) animator.getAnimatedValue(), EPSILON);
- for (int j = 0; j < animatedValues.length - 1; j++) {
- assertTrue(errorMessage(animatedValues), animatedValues[j + 1] >= animatedValues[j]);
}
}
@Test
- public void testGetAnimatedValue_PropertyName() throws Throwable {
- String property = "y";
+ public void testGetAnimatedValue_PropertyName() {
+ PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 100f, -100f);
+ PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0f, 1f);
+ ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(pvhX, pvhY);
+ assertNotNull(animator);
+ TimeInterpolator myInterpolator = new TestInterpolator();
+ animator.setInterpolator(myInterpolator);
+ int sliceNum = 10;
+ for (int i = 0; i <= sliceNum; i++) {
+ float fraction = i / (float) sliceNum;
+ animator.setCurrentFraction(fraction);
+ assertEquals(myInterpolator.getInterpolation(fraction),
+ (float) animator.getAnimatedValue("y"), EPSILON);
- ValueAnimator objAnimator = getAnimator();
- objAnimator.setRepeatCount(0);
- startAnimation(objAnimator);
- assertNotNull(objAnimator);
- float[] animatedValues = getValue(objAnimator, 5, "getAnimatedValue(property)", 100L,
- property);
- for (int j = 0; j < animatedValues.length - 1; j++) {
- assertTrue(errorMessage(animatedValues), animatedValues[j + 1] >= animatedValues[j]);
}
}
@@ -703,24 +738,6 @@
return objAnimator;
}
- private float[] getValue(ValueAnimator animator, int n, String methodName,
- long sleepTime, String property) throws InterruptedException {
- float[] values = new float[n];
- for(int i = 0; i < n; i++){
- SystemClock.sleep(sleepTime);
- float value = 0.0f;
- if(methodName.equals("getAnimatedFraction()")) {
- value = animator.getAnimatedFraction();
- }else if(methodName.equals("getAnimatedValue()")) {
- value = ((Float)animator.getAnimatedValue()).floatValue();
- }else if(methodName.equals("getAnimatedValue(property)")) {
- value = ((Float)animator.getAnimatedValue(property)).floatValue();
- }
- values[i] = value;
- }
- return values;
- }
-
private void startAnimation(final ValueAnimator animator) throws Throwable {
mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator));
}
diff --git a/tests/tests/appwidget/AndroidTest.xml b/tests/tests/appwidget/AndroidTest.xml
index 4b19277..8b193fb 100644
--- a/tests/tests/appwidget/AndroidTest.xml
+++ b/tests/tests/appwidget/AndroidTest.xml
@@ -16,6 +16,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAppWidgetLauncher1.apk" />
diff --git a/tests/tests/background/AndroidTest.xml b/tests/tests/background/AndroidTest.xml
index f0af389..364457e 100644
--- a/tests/tests/background/AndroidTest.xml
+++ b/tests/tests/background/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/binder_ndk/AndroidManifest.xml b/tests/tests/binder_ndk/AndroidManifest.xml
index d4ab466..8be6801 100644
--- a/tests/tests/binder_ndk/AndroidManifest.xml
+++ b/tests/tests/binder_ndk/AndroidManifest.xml
@@ -15,7 +15,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.binder.cts">
+ package="android.binder.cts"
+ android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application android:debuggable="true">
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 969ee21..3ceb414 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -30,7 +30,6 @@
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Telephony;
-import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
import android.test.AndroidTestCase;
@@ -343,6 +342,13 @@
}
}
+ public void testUsageAccessSettings() {
+ PackageManager packageManager = mContext.getPackageManager();
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ assertCanBeHandled(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
+ }
+ }
+
public void testPictureInPictureSettings() {
PackageManager packageManager = mContext.getPackageManager();
if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
diff --git a/tests/tests/dynamic_linker/AndroidManifest.xml b/tests/tests/dynamic_linker/AndroidManifest.xml
index 7a9166d..6a3a270 100644
--- a/tests/tests/dynamic_linker/AndroidManifest.xml
+++ b/tests/tests/dynamic_linker/AndroidManifest.xml
@@ -15,7 +15,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.dynamiclinker">
+ package="com.android.dynamiclinker"
+ android:targetSandboxVersion="2">
<application>
<uses-library android:name="android.test.runner" />
@@ -23,4 +24,4 @@
<instrumentation
android:targetPackage="com.android.dynamiclinker"
android:name="android.support.test.runner.AndroidJUnitRunner" />
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 76552a1..659c56d 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -16,7 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.graphics.cts">
+ package="android.graphics.cts"
+ android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
diff --git a/tests/tests/graphics/AndroidTest.xml b/tests/tests/graphics/AndroidTest.xml
index f6eb47f..0c99b6a 100644
--- a/tests/tests/graphics/AndroidTest.xml
+++ b/tests/tests/graphics/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS Graphics test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsGraphicsTestCases.apk" />
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java
index 7487e55..5218a4fd 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorStateListDrawableTest.java
@@ -18,15 +18,21 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.R;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.ColorStateListDrawable;
import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -78,6 +84,15 @@
}
@Test
+ public void testHasFocusStateSpecified() {
+ assertFalse(mDrawable.hasFocusStateSpecified());
+ final int[][] state = new int[][]{new int[]{1}, new int[]{2, R.attr.state_focused}};
+ final int[] colors = new int[]{Color.MAGENTA, Color.CYAN};
+ mDrawable.setColorStateList(new ColorStateList(state, colors));
+ assertTrue(mDrawable.hasFocusStateSpecified());
+ }
+
+ @Test
public void testAlpha() {
int transBlue = (Color.BLUE & 0xFFFFFF) | 127 << 24;
mDrawable.setColorStateList(ColorStateList.valueOf(transBlue));
@@ -99,6 +114,31 @@
}
@Test
+ public void testColorFilter() {
+ final ColorDrawable colorDrawable = (ColorDrawable) mDrawable.getCurrent();
+ final ColorFilter colorFilter = new LightingColorFilter(Color.GRAY, Color.GREEN);
+
+ assertNull(mDrawable.getColorFilter());
+ mDrawable.setColorFilter(colorFilter);
+ assertEquals(colorFilter, mDrawable.getColorFilter());
+ }
+
+ @Test
+ public void testColorStateListAccess() {
+ final ColorStateListDrawable cslDrawable = new ColorStateListDrawable();
+ final ColorDrawable colorDrawable = (ColorDrawable) cslDrawable.getCurrent();
+ assertNotNull(cslDrawable.getColorStateList());
+ assertEquals(
+ colorDrawable.getColor(),
+ cslDrawable
+ .getColorStateList()
+ .getColorForState(cslDrawable.getState(), Color.YELLOW));
+
+ cslDrawable.setColorStateList(mColorStateList);
+ assertEquals(mColorStateList, cslDrawable.getColorStateList());
+ }
+
+ @Test
public void testSetState() {
ColorDrawable colorDrawable = (ColorDrawable) mDrawable.getCurrent();
assertEquals(colorDrawable.getColor(), mColorStateList.getDefaultColor());
@@ -114,4 +154,79 @@
assertEquals(mDrawable.mutate(), mDrawable);
assertNotEquals(mDrawable.getConstantState(), oldState);
}
+
+ @Test
+ public void testInvalidationCallbackProxy() {
+ final TestCallback callback = new TestCallback();
+ mDrawable.setCallback(callback);
+
+ callback.mInvalidatedDrawable = null;
+ mDrawable.invalidateSelf();
+ assertEquals(mDrawable, callback.mInvalidatedDrawable);
+
+ callback.mInvalidatedDrawable = null;
+ mDrawable.getCurrent().invalidateSelf();
+ assertEquals(mDrawable, callback.mInvalidatedDrawable);
+ }
+
+ @Test
+ public void testScheduleCallbackProxy() {
+ final Runnable runnable = new NoOpRunnable();
+ final long scheduledTime = SystemClock.uptimeMillis() + 100;
+ final TestCallback callback = new TestCallback();
+ mDrawable.setCallback(callback);
+
+ mDrawable.getCurrent().scheduleSelf(runnable, scheduledTime);
+ assertEquals(mDrawable, callback.mScheduledDrawable);
+ assertEquals(runnable, callback.mScheduledRunnable);
+ assertEquals(scheduledTime, callback.mScheduledTime);
+ }
+
+ @Test
+ public void testUnscheduleCallbackProxy() {
+ final Runnable runnable = new NoOpRunnable();
+ final TestCallback callback = new TestCallback();
+ mDrawable.setCallback(callback);
+
+ mDrawable.getCurrent().unscheduleSelf(runnable);
+
+ assertEquals(mDrawable, callback.mUnscheduledDrawable);
+ assertEquals(runnable, callback.mUnscheduledRunnable);
+ }
+
+ private final class TestCallback implements Drawable.Callback {
+ private Drawable mInvalidatedDrawable;
+ private Drawable mScheduledDrawable;
+ private Drawable mUnscheduledDrawable;
+
+ private Runnable mScheduledRunnable;
+ private Runnable mUnscheduledRunnable;
+
+ private long mScheduledTime;
+
+ @Override
+ public void invalidateDrawable(Drawable who) {
+ mInvalidatedDrawable = who;
+ }
+
+ @Override
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ mScheduledDrawable = who;
+ mScheduledRunnable = what;
+ mScheduledTime = when;
+ }
+
+ @Override
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ mUnscheduledDrawable = who;
+ mUnscheduledRunnable = what;
+ }
+ }
+
+ private final class NoOpRunnable implements Runnable {
+ @Override
+ public void run() {
+
+ }
+ }
}
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index f0ebe63..7de8b1e 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -46,6 +46,8 @@
LOCAL_SDK_VERSION := current
LOCAL_NDK_STL_VARIANT := c++_shared
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_CTS_PACKAGE)
# Include the associated library's makefile.
diff --git a/tests/tests/jni/AndroidManifest.xml b/tests/tests/jni/AndroidManifest.xml
index 18ef4c6..9321330 100644
--- a/tests/tests/jni/AndroidManifest.xml
+++ b/tests/tests/jni/AndroidManifest.xml
@@ -15,7 +15,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.jni.cts">
+ package="android.jni.cts"
+ android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application android:extractNativeLibs="true">
diff --git a/tests/tests/jni/TEST_MAPPING b/tests/tests/jni/TEST_MAPPING
new file mode 100644
index 0000000..5d9eea5
--- /dev/null
+++ b/tests/tests/jni/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsJniTestCases"
+ }
+ ]
+}
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index c00ae3b..0228f6e 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <queue>
+#include <regex>
#include <string>
#include <unordered_set>
#include <vector>
@@ -39,37 +40,44 @@
#include <nativehelper/ScopedUtfChars.h>
#if defined(__LP64__)
-static const std::string kSystemLibraryPath = "/system/lib64";
-static const std::string kVendorLibraryPath = "/vendor/lib64";
-static const std::string kProductLibraryPath = "/product/lib64";
+#define LIB_DIR "lib64"
#else
-static const std::string kSystemLibraryPath = "/system/lib";
-static const std::string kVendorLibraryPath = "/vendor/lib";
-static const std::string kProductLibraryPath = "/product/lib";
+#define LIB_DIR "lib"
#endif
+static const std::string kSystemLibraryPath = "/system/" LIB_DIR;
+static const std::string kRuntimeApexLibraryPath = "/apex/com.android.runtime/" LIB_DIR;
+static const std::string kVendorLibraryPath = "/vendor/" LIB_DIR;
+static const std::string kProductLibraryPath = "/product/" LIB_DIR;
+
+static const std::vector<std::regex> kSystemPathRegexes = {
+ std::regex("/system/lib(64)?"),
+ std::regex("/apex/com\\.android\\.[^/]*/lib(64)?"),
+};
+
static const std::string kWebViewPlatSupportLib = "libwebviewchromium_plat_support.so";
-// This is not the complete list - just a small subset
-// of the libraries that should reside in /system/lib
-// for app-compatibility reasons.
-// (in addition to kSystemPublicLibraries)
+// This is not the complete list - just a small subset of the libraries that
+// should not be loaded from vendor locations.
+//
+// TODO(b/124049505): Do not hardcode expected paths here, to allow libraries to
+// migrate between /system and APEXes.
static std::vector<std::string> kSystemLibraries = {
- "libart.so",
- "libandroid_runtime.so",
- "libbinder.so",
- "libcrypto.so",
- "libcutils.so",
- "libexpat.so",
- "libgui.so",
- "libmedia.so",
- "libnativehelper.so",
- "libstagefright.so",
- "libsqlite.so",
- "libui.so",
- "libutils.so",
- "libvorbisidec.so",
- };
+ kRuntimeApexLibraryPath + "/libart.so",
+ kRuntimeApexLibraryPath + "/libnativehelper.so",
+ kSystemLibraryPath + "/libandroid_runtime.so",
+ kSystemLibraryPath + "/libbinder.so",
+ kSystemLibraryPath + "/libcrypto.so",
+ kSystemLibraryPath + "/libcutils.so",
+ kSystemLibraryPath + "/libexpat.so",
+ kSystemLibraryPath + "/libgui.so",
+ kSystemLibraryPath + "/libmedia.so",
+ kSystemLibraryPath + "/libsqlite.so",
+ kSystemLibraryPath + "/libstagefright.so",
+ kSystemLibraryPath + "/libui.so",
+ kSystemLibraryPath + "/libutils.so",
+ kSystemLibraryPath + "/libvorbisidec.so",
+};
static bool is_directory(const char* path) {
struct stat sb;
@@ -107,7 +115,8 @@
// Tests if a file can be loaded or not. Returns empty string on success. On any failure
// returns the error message from dlerror().
-static std::string load_library(JNIEnv* env, jclass clazz, const std::string& path) {
+static std::string load_library(JNIEnv* env, jclass clazz, const std::string& path,
+ bool test_system_load_library) {
// try to load the lib using dlopen().
void *handle = dlopen(path.c_str(), RTLD_NOW);
std::string error;
@@ -127,16 +136,40 @@
// try to load the same lib using System.load() in Java to see if it gives consistent
// result with dlopen.
- static jmethodID load_library = env->GetStaticMethodID(clazz, "loadSharedLibrary",
- "(Ljava/lang/String;)Z");
- jstring jpath = env->NewStringUTF(path.c_str());
- bool loaded_in_java = env->CallStaticBooleanMethod(clazz, load_library, jpath) == JNI_TRUE;
- env->DeleteLocalRef(jpath);
- if (loaded_in_native != loaded_in_java) {
- error = "Inconsistent result for library \"" + path + "\":" +
- " dlopen() was " + (loaded_in_native ? "success" : "failure") +
- ", System.loadLibrary() was " + (loaded_in_java ? "success" : "failure");
- } else if (loaded_in_java) {
+ static jmethodID java_load =
+ env->GetStaticMethodID(clazz, "loadWithSystemLoad", "(Ljava/lang/String;)Ljava/lang/String;");
+ ScopedLocalRef<jstring> jpath(env, env->NewStringUTF(path.c_str()));
+ jstring java_load_errmsg = jstring(env->CallStaticObjectMethod(clazz, java_load, jpath.get()));
+ bool java_load_ok = env->GetStringLength(java_load_errmsg) == 0;
+
+ jstring java_load_lib_errmsg;
+ bool java_load_lib_ok = java_load_ok;
+ if (test_system_load_library && java_load_ok) {
+ // If System.load() works then test System.loadLibrary() too. Cannot test
+ // the other way around since System.loadLibrary() might very well find the
+ // library somewhere else and hence work when System.load() fails.
+ std::string baselib = basename(path.c_str());
+ ScopedLocalRef<jstring> jname(env, env->NewStringUTF(baselib.c_str()));
+ static jmethodID java_load_lib = env->GetStaticMethodID(
+ clazz, "loadWithSystemLoadLibrary", "(Ljava/lang/String;)Ljava/lang/String;");
+ java_load_lib_errmsg = jstring(env->CallStaticObjectMethod(clazz, java_load_lib, jname.get()));
+ java_load_lib_ok = env->GetStringLength(java_load_lib_errmsg) == 0;
+ }
+
+ if (loaded_in_native != java_load_ok || java_load_ok != java_load_lib_ok) {
+ const std::string java_load_error(ScopedUtfChars(env, java_load_errmsg).c_str());
+ error = "Inconsistent result for library \"" + path + "\": dlopen() " +
+ (loaded_in_native ? "succeeded" : "failed (" + error + ")") +
+ ", System.load() " +
+ (java_load_ok ? "succeeded" : "failed (" + java_load_error + ")");
+ if (test_system_load_library) {
+ const std::string java_load_lib_error(ScopedUtfChars(env, java_load_lib_errmsg).c_str());
+ error += ", System.loadLibrary() " +
+ (java_load_lib_ok ? "succeeded" : "failed (" + java_load_lib_error + ")");
+ }
+ }
+
+ if (loaded_in_native && java_load_ok) {
// Unload the shared lib loaded in Java. Since we don't have a method in Java for unloading a
// lib other than destroying the classloader, here comes a trick; we open the same library
// again with dlopen to get the handle for the lib and then calls dlclose twice (since we have
@@ -144,7 +177,7 @@
// the same handle for the same shared lib object.
handle = dlopen(path.c_str(), RTLD_NOW);
dlclose(handle);
- dlclose(handle); // don't delete this line. it's not a mistake.
+ dlclose(handle); // don't delete this line. it's not a mistake (see comment above).
}
return error;
@@ -156,7 +189,7 @@
const std::unordered_set<std::string>& library_search_paths,
const std::unordered_set<std::string>& libraries,
std::vector<std::string>* errors) {
- std::string err = load_library(env, clazz, path);
+ std::string err = load_library(env, clazz, path, /*test_system_load_library=*/true);
bool loaded = err.empty();
// The current restrictions on public libraries:
@@ -329,33 +362,38 @@
std::vector<std::string> library_search_paths = android::base::Split(default_search_paths, ":");
- // Remove everything pointing outside of /system/lib*
+ // Remove everything pointing outside of /system/lib* and
+ // /apex/com.android.*/lib*.
std::unordered_set<std::string> system_library_search_paths;
for (const auto& path : library_search_paths) {
- if (android::base::StartsWith(path, "/system/lib")) {
- system_library_search_paths.insert(path);
+ for (const auto& regex : kSystemPathRegexes) {
+ if (std::regex_match(path, regex)) {
+ system_library_search_paths.insert(path);
+ break;
+ }
}
}
- // This path should be tested too - this is because apps may rely on some
- // libraries being available in /system/${LIB}/
+ // These paths should be tested too - this is because apps may rely on some
+ // libraries being available there.
system_library_search_paths.insert(kSystemLibraryPath);
+ system_library_search_paths.insert(kRuntimeApexLibraryPath);
if (!check_path(env, clazz, kSystemLibraryPath, system_library_search_paths,
system_public_libraries, &errors)) {
success = false;
}
- // Check that the mandatory system libraries are present - the grey list
- for (const auto& name : kSystemLibraries) {
- std::string library = kSystemLibraryPath + "/" + name;
- std::string err = load_library(env, clazz, library);
+ // Check that the mandatory system + APEX libraries are present - the grey list
+ for (const auto& library : kSystemLibraries) {
+ std::string err = load_library(env, clazz, library, /*test_system_load_library=*/false);
if (!err.empty()) {
// The libraries should be present and produce specific dlerror when inaccessible.
if (!not_accessible(err)) {
- errors.push_back("Mandatory system library \"" + library + "\" failed to load with unexpected error: " + err);
- success = false;
+ errors.push_back("Mandatory system library \"" + library +
+ "\" failed to load with unexpected error: " + err);
+ success = false;
}
}
}
@@ -384,4 +422,3 @@
return nullptr;
}
-
diff --git a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
index 59f6cb1..634350f 100644
--- a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
+++ b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
@@ -226,26 +226,39 @@
return nativePath;
}
- private static boolean loadSharedLibrary(String libFilePath) {
+ private static boolean isAlreadyOpenedError(UnsatisfiedLinkError e, String libFilePath) {
+ // If one of the public system libraries are already opened in the bootclassloader, consider
+ // this try as success, because dlopen to the lib is successful.
String baseName = new File(libFilePath).getName();
+ return e.getMessage().contains("Shared library \"" + libFilePath +
+ "\" already opened by ClassLoader") &&
+ Arrays.asList(PUBLIC_SYSTEM_LIBRARIES).contains(baseName);
+ }
+
+ private static String loadWithSystemLoad(String libFilePath) {
try {
System.load(libFilePath);
- // Also ensure that the lib is also accessible via its libname.
- // Drop 'lib' and '.so' from the name
- System.loadLibrary(baseName.substring(3, baseName.length()-3));
- return true;
} catch (UnsatisfiedLinkError e) {
// all other exceptions are just thrown
- if (e.getMessage().contains("Shared library \"" + libFilePath +
- "\" already opened by ClassLoader") &&
- Arrays.asList(PUBLIC_SYSTEM_LIBRARIES).contains(baseName)) {
- // If one of the public system libraries are already opened in the
- // bootclassloader, consider this try as success, because dlopen to the lib
- // is successful.
- return true;
+ if (!isAlreadyOpenedError(e, libFilePath)) {
+ return "System.load() UnsatisfiedLinkError: " + e.getMessage();
}
- return false;
}
+ return "";
+ }
+
+ private static String loadWithSystemLoadLibrary(String libFileName) {
+ // Drop 'lib' and '.so' from the base name
+ String libName = libFileName.substring(3, libFileName.length()-3);
+ try {
+ System.loadLibrary(libName);
+ } catch (UnsatisfiedLinkError e) {
+ if (!isAlreadyOpenedError(e, libFileName)) {
+ return "System.loadLibrary(\"" + libName + "\") UnsatisfiedLinkError: " +
+ e.getMessage();
+ }
+ }
+ return "";
}
// Verify the behaviour of native library loading in class loaders.
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
index 437948f..2ec15de 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
@@ -41,6 +41,7 @@
measurement.setCarrierPhaseUncertainty(7.0);
measurement.setCn0DbHz(8.0);
measurement.setCodeType(GnssMeasurement.CODE_TYPE_C);
+ measurement.setOtherCodeTypeName("G");
measurement.setConstellationType(GnssStatus.CONSTELLATION_GALILEO);
measurement.setMultipathIndicator(GnssMeasurement.MULTIPATH_INDICATOR_DETECTED);
measurement.setPseudorangeRateMetersPerSecond(9.0);
@@ -66,6 +67,7 @@
assertEquals(GnssMeasurement.MULTIPATH_INDICATOR_DETECTED,
measurement.getMultipathIndicator());
assertEquals(GnssMeasurement.CODE_TYPE_C, measurement.getCodeType());
+ assertEquals("G", measurement.getOtherCodeTypeName());
assertEquals(9.0, measurement.getPseudorangeRateMetersPerSecond());
assertEquals(10.0, measurement.getPseudorangeRateUncertaintyMetersPerSecond());
assertEquals(11, measurement.getReceivedSvTimeNanos());
diff --git a/tests/tests/location/src/android/location/cts/GnssTestCase.java b/tests/tests/location/src/android/location/cts/GnssTestCase.java
index 62c38c88..a128c95 100644
--- a/tests/tests/location/src/android/location/cts/GnssTestCase.java
+++ b/tests/tests/location/src/android/location/cts/GnssTestCase.java
@@ -19,7 +19,6 @@
import android.os.SystemProperties;
import android.test.AndroidTestCase;
import android.util.Log;
-import android.content.pm.PackageManager;
/**
* Base Test Case class for all Gnss Tests.
@@ -38,8 +37,7 @@
// On devices using newer hardware, GNSS measurement support is required.
protected boolean isMeasurementTestStrict() {
// Enforce strict measurement test on devices with first API level at least P.
- if (SystemProperties.getInt("ro.product.first_api_level", 0) >= Build.VERSION_CODES.P &&
- !getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (SystemProperties.getInt("ro.product.first_api_level", 0) >= Build.VERSION_CODES.P) {
return true;
}
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index f4f648d..11c2efd 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -17,7 +17,7 @@
<resources>
<array name="exifbyteorderii_jpg">
<item>true</item>
- <item>3112</item>
+ <item>3500</item>
<item>6265</item>
<item>512</item>
<item>288</item>
@@ -61,7 +61,7 @@
<item>0</item>
<item>false</item>
<item>true</item>
- <item>675</item>
+ <item>572</item>
<item>24</item>
<item>0.0</item>
<item>0.0</item>
@@ -175,7 +175,7 @@
<item />
<item />
<item>true</item>
- <item>3081</item>
+ <item>3143</item>
<item>24</item>
<item>37.423</item>
<item>-122.162</item>
diff --git a/tests/tests/media/src/android/media/cts/CodecUtils.java b/tests/tests/media/src/android/media/cts/CodecUtils.java
index ae785b2..15314ef 100644
--- a/tests/tests/media/src/android/media/cts/CodecUtils.java
+++ b/tests/tests/media/src/android/media/cts/CodecUtils.java
@@ -54,6 +54,8 @@
for (int i = 0; i < planes.length; i++) {
mPlanes[i] = new PlaneWrapper(planes[i]);
}
+
+ setCropRect(image.getCropRect());
}
public static ImageWrapper createFromImage(Image image) {
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index 72eddf1..5704b70 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -1122,20 +1122,22 @@
public void release() {
looper.quit();
- if (eglDisplay != EGL10.EGL_NO_DISPLAY) {
- egl10.eglMakeCurrent(eglDisplay,
- EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
- egl10.eglDestroySurface(eglDisplay, eglSurface);
- egl10.eglDestroyContext(eglDisplay, eglContext);
- egl10.eglTerminate(eglDisplay);
- }
- eglDisplay = EGL10.EGL_NO_DISPLAY;
- eglContext = EGL10.EGL_NO_CONTEXT;
- eglSurface = EGL10.EGL_NO_SURFACE;
surface.release();
surfaceTexture.release();
byteBufferIsReady = false;
byteBuffer = null;
+ if (eglDisplay != EGL10.EGL_NO_DISPLAY) {
+ egl10.eglMakeCurrent(eglDisplay,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ egl10.eglDestroySurface(eglDisplay, eglSurface);
+ egl10.eglDestroyContext(eglDisplay, eglContext);
+ //TODO: uncomment following line after fixing crash in GL driver libGLESv2_adreno.so
+ //TODO: see b/123755902
+ //egl10.eglTerminate(eglDisplay);
+ }
+ eglDisplay = EGL10.EGL_NO_DISPLAY;
+ eglContext = EGL10.EGL_NO_CONTEXT;
+ eglSurface = EGL10.EGL_NO_SURFACE;
}
/* Makes our EGL context and surface current. */
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index 6301258..f1594af 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -277,6 +277,8 @@
}
mDecodingSurface = new OutputSurface(w, h);
mDecoder.configure(decoderFormat, mDecodingSurface.getSurface(), null, 0);
+ // only scale to fit scaling mode is supported
+ mDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
mDecoder.start();
mDecoderInputBuffers = mDecoder.getInputBuffers();
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 4ff7274..bd36a54 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -192,7 +192,7 @@
MediaCodec codec = MediaCodec.createByCodecName(info.getName());
assertEquals(codec.getName(), info.getName());
-
+ assertEquals(codec.getCanonicalName(), info.getCanonicalName());
assertEquals(codec.getCodecInfo(), info);
codec.release();
@@ -720,7 +720,8 @@
} else {
for (VideoCapabilities.PerformancePoint p : pps) {
Log.d(TAG, "got performance point "
- + p.width + " x " + p.height + " x " + p.frameRate);
+ + p.macroBlocks + "block @ " + p.macroBlockRate / p.macroBlocks
+ + "fps (max " + p.frameRate + "fps)");
}
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaFormatTest.java b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
index c5b3ed4..2beae2b 100644
--- a/tests/tests/media/src/android/media/cts/MediaFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
@@ -585,4 +585,54 @@
} catch (IllegalArgumentException e) {
}
}
+
+ public void testMediaFormatConstructors() {
+ MediaFormat format;
+ {
+ format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 6);
+ assertEquals(MediaFormat.MIMETYPE_AUDIO_AAC, format.getString(MediaFormat.KEY_MIME));
+ assertEquals(48000, format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
+ assertEquals(6, format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
+ assertEquals(3, format.getKeys().size());
+ assertEquals(0, format.getFeatures().size());
+ }
+
+ {
+ format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080);
+ assertEquals(MediaFormat.MIMETYPE_VIDEO_AVC, format.getString(MediaFormat.KEY_MIME));
+ assertEquals(1920, format.getInteger(MediaFormat.KEY_WIDTH));
+ assertEquals(1080, format.getInteger(MediaFormat.KEY_HEIGHT));
+ assertEquals(3, format.getKeys().size());
+ assertEquals(0, format.getFeatures().size());
+ }
+
+ {
+ format = MediaFormat.createSubtitleFormat(MediaFormat.MIMETYPE_TEXT_VTT, "und");
+ assertEquals(MediaFormat.MIMETYPE_TEXT_VTT, format.getString(MediaFormat.KEY_MIME));
+ assertEquals("und", format.getString(MediaFormat.KEY_LANGUAGE));
+ assertEquals(2, format.getKeys().size());
+ assertEquals(0, format.getFeatures().size());
+
+ format.setFeatureEnabled("feature1", false);
+
+ // also test dup
+ MediaFormat other = new MediaFormat(format);
+ format.setString(MediaFormat.KEY_LANGUAGE, "un");
+ other.setInteger(MediaFormat.KEY_IS_DEFAULT, 1);
+ other.setFeatureEnabled("feature1", true);
+
+ assertEquals(MediaFormat.MIMETYPE_TEXT_VTT, format.getString(MediaFormat.KEY_MIME));
+ assertEquals("un", format.getString(MediaFormat.KEY_LANGUAGE));
+ assertEquals(2, format.getKeys().size());
+ assertFalse(format.getFeatureEnabled("feature1"));
+ assertEquals(1, format.getFeatures().size());
+
+ assertEquals(MediaFormat.MIMETYPE_TEXT_VTT, other.getString(MediaFormat.KEY_MIME));
+ assertEquals("und", other.getString(MediaFormat.KEY_LANGUAGE));
+ assertEquals(1, other.getInteger(MediaFormat.KEY_IS_DEFAULT));
+ assertEquals(3, other.getKeys().size());
+ assertTrue(other.getFeatureEnabled("feature1"));
+ assertEquals(1, other.getFeatures().size());
+ }
+ }
}
diff --git a/tests/tests/net/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
index 0bfb650..2a57c10 100644
--- a/tests/tests/net/AndroidManifest.xml
+++ b/tests/tests/net/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
index 71cf3f2..ff20d4d 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
@@ -36,6 +36,7 @@
import android.os.ParcelFileDescriptor;
import android.provider.Telephony;
import android.service.notification.Adjustment;
+import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
@@ -250,6 +251,52 @@
assertTrue(replyFound);
}
+ @Test
+ public void testOnActionInvoked_methodExists() throws Exception {
+ setUpListeners();
+ final Intent intent = new Intent(Intent.ACTION_MAIN, Telephony.Threads.CONTENT_URI);
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.setAction(Intent.ACTION_MAIN);
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+ Notification.Action action = new Notification.Action.Builder(null, "",
+ pendingIntent).build();
+ // This method has to exist and the call cannot fail
+ mNotificationAssistantService.onActionInvoked("", action,
+ NotificationAssistantService.SOURCE_FROM_APP);
+ }
+
+ @Test
+ public void testOnNotificationDirectReplied_methodExists() throws Exception {
+ setUpListeners();
+ // This method has to exist and the call cannot fail
+ mNotificationAssistantService.onNotificationDirectReplied("");
+ }
+
+ @Test
+ public void testOnNotificationExpansionChanged_methodExists() throws Exception {
+ setUpListeners();
+ // This method has to exist and the call cannot fail
+ mNotificationAssistantService.onNotificationExpansionChanged("", true, true);
+ }
+
+ @Test
+ public void testOnNotificationsSeen_methodExists() throws Exception {
+ setUpListeners();
+ // This method has to exist and the call cannot fail
+ mNotificationAssistantService.onNotificationsSeen(new ArrayList<String>());
+ }
+
+ @Test
+ public void testOnSuggestedReplySent_methodExists() throws Exception {
+ setUpListeners();
+ // This method has to exist and the call cannot fail
+ mNotificationAssistantService.onSuggestedReplySent("", "",
+ NotificationAssistantService.SOURCE_FROM_APP);
+ }
+
private StatusBarNotification getFirstNotificationFromPackage(String PKG)
throws InterruptedException {
StatusBarNotification sbn = mNotificationListenerService.mPosted.poll(SLEEP_TIME,
diff --git a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java
index a4f956b..0b03458 100644
--- a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorTest.java
@@ -151,8 +151,8 @@
}
@Test
- public void testToString() {
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+ public void testToString() throws Exception {
+ ParcelFileDescriptor pfd = makeParcelFileDescriptor(getContext());
assertNotNull(pfd.toString());
}
@@ -206,8 +206,8 @@
}
@Test
- public void testGetFileDescriptor() {
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+ public void testGetFileDescriptor() throws Exception {
+ ParcelFileDescriptor pfd = makeParcelFileDescriptor(getContext());
assertNotNull(pfd.getFileDescriptor());
ParcelFileDescriptor p = new ParcelFileDescriptor(pfd);
@@ -215,8 +215,8 @@
}
@Test
- public void testDescribeContents() {
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+ public void testDescribeContents() throws Exception{
+ ParcelFileDescriptor pfd = makeParcelFileDescriptor(getContext());
assertTrue((Parcelable.CONTENTS_FILE_DESCRIPTOR & pfd.describeContents()) != 0);
}
diff --git a/tests/tests/permission/AndroidManifest.xml b/tests/tests/permission/AndroidManifest.xml
index 928da95..5400c7d 100644
--- a/tests/tests/permission/AndroidManifest.xml
+++ b/tests/tests/permission/AndroidManifest.xml
@@ -32,33 +32,8 @@
android:permissionGroup="android.permission.cts.groupC"
android:description="@string/perm_c" />
- <!-- for android.permission.cts.PermissionUsage -->
- <permission android:name="android.permission.cts.D"
- android:usageInfoRequired="true" />
-
- <!-- for android.permission.cts.PermissionUsage and LocationAccessCheckTest -->
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
- android:dataSentOffDevice="no"
- android:dataSharedWithThirdParty="no"
- android:dataUsedForMonetization="no"
- android:dataRetentionTime="notRetained" />
-
- <!-- for android.permission.cts.PermissionUsage -->
- <uses-permission android:name="android.permission.READ_PHONE_STATE"
- android:dataSentOffDevice="yes"
- android:dataSharedWithThirdParty="yes"
- android:dataUsedForMonetization="yes"
- android:dataRetentionTime="32" />
-
- <!-- for android.permission.cts.PermissionUsage -->
- <uses-permission android:name="android.permission.RECORD_AUDIO"
- android:dataSentOffDevice="userTriggered"
- android:dataSharedWithThirdParty="userTriggered"
- android:dataUsedForMonetization="userTriggered"
- android:dataRetentionTime="unlimited" />
-
- <!-- for android.permission.cts.PermissionUsage -->
- <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <!-- for android.permission.cts.LocationAccessCheckTest -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- for android.permission.cts.PermissionGroupChange -->
<permission-group android:description="@string/perm_group_b"
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java b/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java
deleted file mode 100644
index 39c66a6..0000000
--- a/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.permission.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
-import android.content.pm.UsesPermissionInfo;
-import android.test.InstrumentationTestCase;
-
-import org.junit.Before;
-
-public final class PermissionUsageTest extends InstrumentationTestCase {
- private PackageManager mPm;
- private Context mContext;
-
- @Override
- @Before
- public void setUp() throws Exception {
- mContext = getInstrumentation().getTargetContext();
- mPm = mContext.getPackageManager();
- assertNotNull(mPm);
- }
-
- private UsesPermissionInfo getUsesPermissionInfo(String permission) throws Exception {
- PackageInfo info = mPm.getPackageInfo(mContext.getPackageName(),
- PackageManager.GET_PERMISSIONS);
- assertNotNull(info);
- assertNotNull(info.usesPermissions);
- for (UsesPermissionInfo upi : info.usesPermissions) {
- if (permission.equals(upi.getPermission())) {
- return upi;
- }
- }
- return null;
- }
-
- public void testBasic() throws Exception {
- UsesPermissionInfo upi = getUsesPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION);
- assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataSentOffDevice());
- assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataSharedWithThirdParty());
- assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataUsedForMonetization());
- assertEquals(UsesPermissionInfo.RETENTION_NOT_RETAINED, upi.getDataRetention());
- }
-
- public void testRetentionWeeks() throws Exception {
- UsesPermissionInfo upi
- = getUsesPermissionInfo(Manifest.permission.READ_PHONE_STATE);
- assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataSentOffDevice());
- assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataSharedWithThirdParty());
- assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataUsedForMonetization());
- assertEquals(UsesPermissionInfo.RETENTION_SPECIFIED, upi.getDataRetention());
- assertEquals(32, upi.getDataRetentionWeeks());
- }
-
- public void testUserTriggered() throws Exception {
- UsesPermissionInfo upi
- = getUsesPermissionInfo(Manifest.permission.RECORD_AUDIO);
- assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED, upi.getDataSentOffDevice());
- assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED,
- upi.getDataSharedWithThirdParty());
- assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED,
- upi.getDataUsedForMonetization());
- assertEquals(UsesPermissionInfo.RETENTION_UNLIMITED, upi.getDataRetention());
- }
-
- public void testUndefined() throws Exception {
- UsesPermissionInfo upi
- = getUsesPermissionInfo(Manifest.permission.READ_CALENDAR);
- assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataSentOffDevice());
- assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataSharedWithThirdParty());
- assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataUsedForMonetization());
- assertEquals(UsesPermissionInfo.RETENTION_UNDEFINED, upi.getDataRetention());
- }
-
- public void testUsageInfoRequired() throws Exception {
- PermissionInfo pi = mPm.getPermissionInfo("android.permission.cts.D", 0);
- assertTrue(pi.usageInfoRequired);
- }
-}
diff --git a/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java
index cf49f50..96eef77 100644
--- a/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.UsesPermissionInfo;
import android.os.Process;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -65,10 +64,9 @@
String pkg = pkgs[0];
final PackageInfo packageInfo = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
- assertNotNull("No permissions found for " + pkg, packageInfo.usesPermissions);
+ assertNotNull("No permissions found for " + pkg, packageInfo.requestedPermissions);
- for (UsesPermissionInfo permInfo : packageInfo.usesPermissions) {
- final String permission = permInfo.getPermission();
+ for (String permission : packageInfo.requestedPermissions) {
Log.d(LOG_TAG, "SHELL as " + pkg + " uses permission " + permission);
assertFalse("SHELL as " + pkg + " contains the illegal permission " + permission,
blacklist.contains(permission));
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 836214c..c2aa5fe 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -2286,7 +2286,7 @@
<!-- Allows an application to start activities from background
@hide -->
<permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
- android:protectionLevel="signature|privileged|vendorPrivileged|oem" />
+ android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
<!-- @SystemApi Must be required by activities that handle the intent action
{@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
diff --git a/tests/tests/preference/AndroidTest.xml b/tests/tests/preference/AndroidTest.xml
index 4287b76..1980c38 100644
--- a/tests/tests/preference/AndroidTest.xml
+++ b/tests/tests/preference/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/preference/OWNERS b/tests/tests/preference/OWNERS
index d20511f..827134e 100644
--- a/tests/tests/preference/OWNERS
+++ b/tests/tests/preference/OWNERS
@@ -1,2 +1,3 @@
+lpf@google.com
pavlis@google.com
clarabayarri@google.com
diff --git a/tests/tests/preference2/AndroidTest.xml b/tests/tests/preference2/AndroidTest.xml
index a3fb234..452702d 100644
--- a/tests/tests/preference2/AndroidTest.xml
+++ b/tests/tests/preference2/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsPreference2TestCases.apk" />
diff --git a/tests/tests/preference2/OWNERS b/tests/tests/preference2/OWNERS
new file mode 100644
index 0000000..827134e
--- /dev/null
+++ b/tests/tests/preference2/OWNERS
@@ -0,0 +1,3 @@
+lpf@google.com
+pavlis@google.com
+clarabayarri@google.com
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
index 4f0850a..792a00b 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
@@ -197,34 +197,6 @@
}
}
- @Test
- public void testHash() throws Exception {
- final ContentResolver resolver = getContext().getContentResolver();
-
- final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, mExternalImages);
- SystemClock.sleep(500);
-
- final String expected = Arrays
- .toString(HexEncoding.decode("dd41258ce8d306163f3b727603cb064be81973db"));
-
- // We can force hash to be generated by requesting canonicalization
- resolver.canonicalize(uri);
- try (Cursor c = resolver.query(uri, new String[] { MediaColumns.HASH }, null, null)) {
- assertTrue(c.moveToFirst());
- assertEquals(expected, Arrays.toString(c.getBlob(0)));
- }
-
- // Make sure that editing image results in a different hash
- try (OutputStream out = resolver.openOutputStream(uri, "wa")) {
- out.write(42);
- }
- SystemClock.sleep(500);
- try (Cursor c = resolver.query(uri, new String[] { MediaColumns.HASH }, null, null)) {
- assertTrue(c.moveToFirst());
- assertNotEquals(expected, Arrays.toString(c.getBlob(0)));
- }
- }
-
private long getExternalPackageSize() throws Exception {
final StorageManager storage = getContext().getSystemService(StorageManager.class);
final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreTrashTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreTrashTest.java
deleted file mode 100644
index 97cd1ff..0000000
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreTrashTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.cts.MediaStoreTest.TAG;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.SystemClock;
-import android.provider.MediaStore;
-import android.provider.MediaStore.MediaColumns;
-import android.support.test.InstrumentationRegistry;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class MediaStoreTrashTest {
- private Context mContext;
- private ContentResolver mResolver;
-
- private Uri mExternalImages;
-
- @Parameter(0)
- public String mVolumeName;
-
- @Parameters
- public static Iterable<? extends Object> data() {
- return ProviderTestUtils.getSharedVolumeNames();
- }
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
- mResolver = mContext.getContentResolver();
-
- Log.d(TAG, "Using volume " + mVolumeName);
- mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
- }
-
- @Test
- public void testTrashUntrash() throws Exception {
- final Uri insertUri = mExternalImages;
- final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, insertUri);
- final long id = ContentUris.parseId(uri);
-
- // Default is not trashed, and no expiration date
- try (Cursor c = mResolver.query(uri,
- new String[] { MediaColumns.IS_TRASHED, MediaColumns.DATE_EXPIRES }, null, null)) {
- assertTrue(c.moveToFirst());
- assertEquals(0, c.getInt(0));
- assertTrue(c.isNull(1));
- }
- assertTrue(containsId(insertUri, id));
- assertTrue(containsId(MediaStore.setIncludeTrashed(insertUri), id));
-
- // Trash should expire roughly 2 days from now
- MediaStore.trash(mContext, uri);
- try (Cursor c = mResolver.query(uri,
- new String[] { MediaColumns.IS_TRASHED, MediaColumns.DATE_EXPIRES }, null, null)) {
- assertTrue(c.moveToFirst());
- assertEquals(1, c.getInt(0));
- assertMostlyEquals((System.currentTimeMillis() + (2 * DateUtils.DAY_IN_MILLIS)) / 1000,
- c.getLong(1), 30);
- }
- assertFalse(containsId(insertUri, id));
- assertTrue(containsId(MediaStore.setIncludeTrashed(insertUri), id));
-
- // Untrash should bring us back
- MediaStore.untrash(mContext, uri);
- try (Cursor c = mResolver.query(uri,
- new String[] { MediaColumns.IS_TRASHED, MediaColumns.DATE_EXPIRES }, null, null)) {
- assertTrue(c.moveToFirst());
- assertEquals(0, c.getInt(0));
- assertTrue(c.isNull(1));
- }
- assertTrue(containsId(insertUri, id));
- assertTrue(containsId(MediaStore.setIncludeTrashed(insertUri), id));
- }
-
- @Test
- public void testTrashExecutes() throws Exception {
- final Uri insertUri = mExternalImages;
- final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, insertUri);
-
- MediaStore.trash(mContext, uri, 1);
-
- // Force idle maintenance to run
- ProviderTestUtils.executeShellCommand(
- "cmd jobscheduler run -f com.android.providers.media -200",
- InstrumentationRegistry.getInstrumentation().getUiAutomation());
-
- // Wait around for item to be deleted
- final long timeout = SystemClock.elapsedRealtime() + DateUtils.MINUTE_IN_MILLIS;
- while (SystemClock.elapsedRealtime() < timeout) {
- try (Cursor c = mResolver.query(uri, null, null, null)) {
- Log.v(TAG, "Count " + c.getCount());
- if (c.getCount() == 0) {
- return;
- }
- }
- SystemClock.sleep(500);
- }
-
- fail("Timed out waiting for job to delete trashed item");
- }
-
- private boolean containsId(Uri uri, long id) {
- try (Cursor c = mResolver.query(uri,
- new String[] { MediaColumns._ID }, null, null)) {
- while (c.moveToNext()) {
- if (c.getLong(0) == id) return true;
- }
- }
- return false;
- }
-
- private static void assertMostlyEquals(long expected, long actual, long delta) {
- if (Math.abs(expected - actual) > delta) {
- fail("Expected roughly " + expected + " but was " + actual);
- }
- }
-}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
index de1b40a..24f7ed4 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
@@ -44,12 +44,14 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -148,6 +150,58 @@
}
@Test
+ public void testInsertDownload() throws Exception {
+ final String content = "<html><body>Content</body></html>";
+ final String displayName = "cts" + System.nanoTime();
+ final String mimeType = "text/html";
+ final Uri downloadUri = Uri.parse("https://developer.android.com/overview.html");
+ final Uri refererUri = Uri.parse("https://www.android.com");
+
+ final MediaStore.PendingParams params = new MediaStore.PendingParams(
+ Downloads.EXTERNAL_CONTENT_URI, displayName, mimeType);
+ params.setDownloadUri(downloadUri);
+ params.setRefererUri(refererUri);
+
+ final Uri pendingUri = MediaStore.createPending(mContext, params);
+ assertNotNull(pendingUri);
+ mAddedUris.add(pendingUri);
+ final Uri publishUri;
+ try (MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri)) {
+ try (PrintWriter pw = new PrintWriter(session.openOutputStream())) {
+ pw.print(content);
+ }
+ try (OutputStream out = session.openOutputStream()) {
+ out.write(content.getBytes(StandardCharsets.UTF_8));
+ }
+ publishUri = session.publish();
+ }
+
+ try (Cursor cursor = mContentResolver.query(publishUri, null, null, null, null)) {
+ assertEquals(1, cursor.getCount());
+
+ cursor.moveToNext();
+ assertEquals(mimeType,
+ cursor.getString(cursor.getColumnIndex(Downloads.MIME_TYPE)));
+ assertEquals(displayName,
+ cursor.getString(cursor.getColumnIndex(Downloads.DISPLAY_NAME)));
+ assertEquals(downloadUri.toString(),
+ cursor.getString(cursor.getColumnIndex(Downloads.DOWNLOAD_URI)));
+ assertEquals(refererUri.toString(),
+ cursor.getString(cursor.getColumnIndex(Downloads.REFERER_URI)));
+ }
+
+ final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+ try (InputStream in = mContentResolver.openInputStream(publishUri)) {
+ final byte[] buf = new byte[512];
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ actual.write(buf, 0, bytesRead);
+ }
+ }
+ assertEquals(content, actual.toString(StandardCharsets.UTF_8.name()));
+ }
+
+ @Test
public void testUpdateDownload() throws Exception {
final String displayName = "cts" + System.nanoTime();
final MediaStore.PendingParams params = new MediaStore.PendingParams(
@@ -268,7 +322,7 @@
private Uri insertImage(String displayName, String description,
File file, String mimeType, int resourceId) throws Exception {
file.createNewFile();
- try (InputStream in = mContext.getResources().openRawResource(R.raw.scenery);
+ try (InputStream in = mContext.getResources().openRawResource(resourceId);
OutputStream out = new FileOutputStream(file)) {
FileUtils.copy(in, out);
}
diff --git a/tests/tests/sax/AndroidTest.xml b/tests/tests/sax/AndroidTest.xml
index f81aa67..a9c5ba7 100644
--- a/tests/tests/sax/AndroidTest.xml
+++ b/tests/tests/sax/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS SAX test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index ef7a9ec..6f09886 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -53,7 +53,7 @@
private static final String TEST_APP_PACKAGE = "android.telecom.cts.redirectiontestapp";
private static final String TEST_APP_COMPONENT = TEST_APP_PACKAGE
+ "/android.telecom.cts.redirectiontestapp.CtsCallRedirectionService";
- private static final String ROLE_CALL_REDIRECTION = "android.app.role.PROXY_CALLING_APP";
+ private static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
private static final Uri SAMPLE_HANDLE = Uri.fromParts(PhoneAccount.SCHEME_TEL, "0001112222",
null);
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
index 3abf52f..7cd2b13 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
@@ -43,8 +43,8 @@
public class CtsRoleManagerAdapter {
private static final String TAG = CtsRoleManagerAdapter.class.getSimpleName();
- private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
- private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+ private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
+ private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER";
private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
"telecom add-or-remove-call-companion-app";
private static final String COMMAND_SET_AUTO_MODE_APP = "telecom set-test-auto-mode-app";
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 83f3995..5ccfa3c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -62,7 +62,7 @@
"android.telecom.cts.screeningtestapp/"
+ "android.telecom.cts.screeningtestapp.CtsCallScreeningService";
private static final int ASYNC_TIMEOUT = 10000;
- private static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING_APP";
+ private static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
private static final CallIdentification SAMPLE_CALL_ID = new CallIdentification.Builder()
.setName("Joe's Laundromat")
.setDescription("1234 Dirtysocks Lane, Cleanville, USA")
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
index ef24240..ead51f4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
@@ -45,8 +45,8 @@
public class ThirdPartyInCallServiceTest extends BaseTelecomTestWithMockServices {
private static final String TAG = ThirdPartyInCallServiceTest.class.getSimpleName();
- private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
- private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+ private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
+ private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER";
private static final Uri sTestUri = Uri.parse("tel:555-TEST");
private Context mContext;
private UiModeManager mUiModeManager;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
index 7b5024b..eaa5722 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
@@ -17,7 +17,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
import android.os.Parcel;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
@@ -35,6 +34,7 @@
import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthNr;
import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -49,8 +49,7 @@
*/
public class CellInfoTest extends AndroidTestCase{
private final Object mLock = new Object();
- private TelephonyManager mTelephonyManager;
- private static ConnectivityManager mCm;
+ private TelephonyManager mTm;
private static final String TAG = "android.telephony.cts.CellInfoTest";
// Maximum and minimum possible RSSI values(in dbm).
private static final int MAX_RSSI = -10;
@@ -122,12 +121,17 @@
private PackageManager mPm;
+ private boolean isCamped() {
+ ServiceState ss = mTm.getServiceState();
+ if (ss == null) return false;
+ return (ss.getState() == ServiceState.STATE_IN_SERVICE
+ || ss.getState() == ServiceState.STATE_EMERGENCY_ONLY);
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
- mTelephonyManager =
- (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
- mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ mTm = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
mPm = getContext().getPackageManager();
}
@@ -138,14 +142,11 @@
return;
}
- if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
- Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
- return;
- }
+ if (!isCamped()) fail("Device is not camped to a cell");
// getAllCellInfo should never return null, and there should
// be at least one entry.
- List<CellInfo> allCellInfo = mTelephonyManager.getAllCellInfo();
+ List<CellInfo> allCellInfo = mTm.getAllCellInfo();
assertNotNull("TelephonyManager.getAllCellInfo() returned NULL!", allCellInfo);
assertTrue("TelephonyManager.getAllCellInfo() returned zero-length list!",
allCellInfo.size() > 0);
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
index cb87173..a31babf 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
@@ -86,28 +86,38 @@
Set<Class<?>> types = new HashSet<Class<?>>();
- Class<?> type = getSignalStrengthTypeForNetworkType(mTm.getDataNetworkType());
- if (type != null) types.add(type);
+ Class<?> dataType = getSignalStrengthTypeForNetworkType(mTm.getDataNetworkType());
+ if (dataType != null) types.add(dataType);
- type = getSignalStrengthTypeForNetworkType(mTm.getNetworkType());
- if (type != null) types.add(type);
+ Class<?> voiceType = getSignalStrengthTypeForNetworkType(mTm.getNetworkType());
- // Blocked by b/123096279
- /*
+ // Check if camped for Voice-Only
+ if (dataType == null && voiceType != null) {
+ types.add(voiceType);
+ }
+
+ // Check for SRLTE
+ if (dataType != null && voiceType != null
+ && dataType.equals(CellSignalStrengthLte.class)
+ && voiceType.equals(CellSignalStrengthCdma.class)) {
+ types.add(voiceType);
+ }
+
+ // Check for NR
+ if (isUsingEnDc()) {
+ types.add(CellSignalStrengthNr.class);
+ }
+
for (CellSignalStrength css : signalStrengths) {
assertTrue("Invalid SignalStrength type detected" + css.getClass(),
- types.contains(css.getClass())
- || css instanceof CellSignalStrengthNr && isUsingEnDc());
+ types.contains(css.getClass()));
}
- */
}
/** Check whether the device is LTE + NR dual connected */
private boolean isUsingEnDc() {
ServiceState ss = mTm.getServiceState();
- return false;
- // blocked by b/123096279
- // return ss != null && ss.getNrStatus() == NR_STATUS_CONNECTED;
+ return ss != null && ss.getNrStatus() == NR_STATUS_CONNECTED;
}
/** Get the CellSignalStrength class type that should be returned when using a network type */
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index bb5857e..914660d 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -41,6 +41,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionPlan;
+import android.telephony.TelephonyManager;
import com.android.compatibility.common.util.SystemUtil;
import com.android.internal.util.ArrayUtils;
@@ -167,7 +168,7 @@
@Test
public void testIsUsableSubscriptionId() throws Exception {
if (!isSupported()) return;
- assertTrue(SubscriptionManager.isUsableSubIdValue(mSubId));
+ assertTrue(SubscriptionManager.isUsableSubscriptionId(mSubId));
}
@Test
@@ -405,6 +406,15 @@
}
@Test
+ public void testSubscriptionInfoCarrierId() {
+ if (!isSupported()) return;
+
+ SubscriptionInfo info = mSm.getActiveSubscriptionInfo(mSubId);
+ int carrierId = info.getCarrierId();
+ assertTrue(carrierId >= TelephonyManager.UNKNOWN_CARRIER_ID);
+ }
+
+ @Test
public void testSettingSubscriptionMeteredNess() throws Exception {
if (!isSupported()) return;
diff --git a/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java b/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java
index 4732193..8058679 100644
--- a/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java
+++ b/tests/tests/telephony4/src/android/telephony4/cts/SimRestrictedApisTest.java
@@ -67,21 +67,6 @@
}
/**
- * Tests the TelephonyManager.setLine1NumberForDisplay(long, string, string) API. This makes a
- * call to setLine1NumberForDisplay() API and expects a SecurityException since the test apk is
- * not signed by the certificate on the SIM.
- */
- public void testSetLine1NumberForDisplay2() {
- try {
- if (isSimCardPresent()) {
- mTelephonyManager.setLine1NumberForDisplay(0, "", "");
- fail("Expected SecurityException. App doesn't have carrier privileges.");
- }
- } catch (SecurityException expected) {
- }
- }
-
- /**
* Tests the TelephonyManager.iccOpenLogicalChannel() API. This makes a call to
* iccOpenLogicalChannel() API and expects a SecurityException since the test apk is not signed
* by certificate on the SIM.
@@ -172,34 +157,6 @@
}
/**
- * Tests the TelephonyManager.nvWriteItem() API. This makes a call to nvWriteItem() API and
- * expects a SecurityException since the test apk is not signed by a certificate on the SIM.
- */
- public void testNvWriteItem() {
- try {
- if (isSimCardPresent()) {
- mTelephonyManager.nvWriteItem(0, "");
- fail("Expected SecurityException. App doesn't have carrier privileges.");
- }
- } catch (SecurityException expected) {
- }
- }
-
- /**
- * Tests the TelephonyManager.nvWriteCdmaPrl() API. This makes a call to nvWriteCdmaPrl() API
- * and expects a SecurityException since the test apk is not signed by a certificate on the SIM.
- */
- public void testNvWriteCdmaPrl() {
- try {
- if (isSimCardPresent()) {
- mTelephonyManager.nvWriteCdmaPrl(null);
- fail("Expected SecurityException. App doesn't have carrier privileges.");
- }
- } catch (SecurityException expected) {
- }
- }
-
- /**
* Tests the TelephonyManager.nvResetConfig() API. This makes a call to nvResetConfig() API and
* expects a SecurityException since the test apk is not signed by a certificate on the SIM.
*/
diff --git a/tests/tests/theme/Android.bp b/tests/tests/theme/Android.bp
new file mode 100644
index 0000000..607f63f
--- /dev/null
+++ b/tests/tests/theme/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "CtsThemeDeviceTestCases",
+ defaults: ["cts_defaults"],
+
+ static_libs: ["ctstestrunner"],
+
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+
+ srcs: ["src/**/*.java"],
+
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+
+ sdk_version: "current",
+}
diff --git a/tests/tests/theme/Android.mk b/tests/tests/theme/Android.mk
deleted file mode 100644
index ff8536b..0000000
--- a/tests/tests/theme/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsThemeDeviceTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
index 57462b6..955d51f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Mockito.mock;
@@ -26,6 +27,7 @@
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -137,6 +139,17 @@
}
@Test
+ public void testSetBlendMode() {
+ assertEdgeEffect(edgeEffect -> {
+ edgeEffect.setBlendMode(null);
+ assertNull(edgeEffect.getBlendMode());
+ edgeEffect.setBlendMode(EdgeEffect.DEFAULT_BLEND_MODE);
+ assertEquals(BlendMode.SRC_ATOP, edgeEffect.getBlendMode());
+ edgeEffect.onPull(1);
+ });
+ }
+
+ @Test
public void testOnPullWithDisplacement() {
assertEdgeEffect(edgeEffect -> {
edgeEffect.onPull(1, 0);
diff --git a/tests/tests/util/AndroidTest.xml b/tests/tests/util/AndroidTest.xml
index 92c1e14..7f11f18 100644
--- a/tests/tests/util/AndroidTest.xml
+++ b/tests/tests/util/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS Util test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsUtilTestCases.apk" />
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index dabbc1a..925f3e2 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -31,6 +31,15 @@
android:supportsRtl="true">
<uses-library android:name="android.test.runner" />
+ <activity android:name="android.app.Activity"
+ android:label="Empty Activity"
+ android:theme="@style/ViewStyleTestTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.view.cts.ViewStubCtsActivity"
android:screenOrientation="locked"
android:label="ViewStubCtsActivity">
diff --git a/tests/tests/view/jni/Android.bp b/tests/tests/view/jni/Android.bp
new file mode 100644
index 0000000..61932fc
--- /dev/null
+++ b/tests/tests/view/jni/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test_library {
+
+ name: "libctsview_jni",
+
+ cflags: ["-Werror"],
+
+ gtest: false,
+
+ srcs: [
+ "CtsViewJniOnLoad.cpp",
+ "android_view_cts_ASurfaceControlTest.cpp",
+ "android_view_cts_ChoreographerNativeTest.cpp",
+ ],
+
+ shared_libs: [
+ "libandroid",
+ "libnativehelper_compat_libc++",
+ "liblog",
+ "libsync",
+ ],
+
+ stl: "c++_static",
+
+ sdk_version: "current",
+
+}
diff --git a/tests/tests/view/jni/Android.mk b/tests/tests/view/jni/Android.mk
deleted file mode 100644
index 85c073b..0000000
--- a/tests/tests/view/jni/Android.mk
+++ /dev/null
@@ -1,38 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libctsview_jni
-
-LOCAL_CFLAGS += -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- CtsViewJniOnLoad.cpp \
- android_view_cts_ASurfaceControlTest.cpp \
- android_view_cts_ChoreographerNativeTest.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog libsync
-
-LOCAL_NDK_STL_VARIANT := c++_static
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/view/res/layout/view_style_layout.xml b/tests/tests/view/res/layout/view_style_layout.xml
new file mode 100644
index 0000000..dd488ef
--- /dev/null
+++ b/tests/tests/view/res/layout/view_style_layout.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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">
+ <View android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/view1"
+ android:paddingTop="7dp"
+ style="@style/ExplicitStyle1" />
+
+ <View android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/view2"
+ style="@style/ExplicitStyle2" />
+
+ <View android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/view3" />
+
+ <View android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/view4"
+ style="?android:attr/textAppearanceLarge"/>
+
+ <Button android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/button1" />
+
+ <Button android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/button2"
+ style="@style/ExplicitStyle1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/view/res/values/styles.xml b/tests/tests/view/res/values/styles.xml
index 5e47363..ab984e8 100644
--- a/tests/tests/view/res/values/styles.xml
+++ b/tests/tests/view/res/values/styles.xml
@@ -187,4 +187,26 @@
<item name="android:windowContentTransitions">false</item>
<item name="android:windowAnimationStyle">@null</item>
</style>
+
+ <style name="ViewStyleTestTheme" parent="@android:Theme.Material">
+ <item name="android:buttonStyle">@style/MyButtonStyle</item>
+ </style>
+
+ <style name="MyButtonStyle" parent="@style/MyButtonStyleParent">
+ <item name="android:paddingTop">3dp</item>
+ </style>
+
+ <style name="MyButtonStyleParent">
+ <item name="android:textColor">#ff00ff</item>
+ </style>
+
+ <style name="ExplicitStyle1" parent="@style/ParentOfExplicitStyle1">
+ <item name="android:padding">1dp</item>
+ </style>
+
+ <style name="ParentOfExplicitStyle1">
+ <item name="android:paddingLeft">2dp</item>
+ </style>
+
+ <style name="ExplicitStyle2" />
</resources>
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index 3460525..7d6228d 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
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;
@@ -26,6 +27,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -53,6 +55,9 @@
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class LayoutInflaterTest {
@@ -412,6 +417,39 @@
assertNotNull(container.findViewById(R.id.include_layout_from_attr));
}
+ // API : LayoutInflater#onCreateView(Context, View, String, AttributeSet)
+ // API : LayoutInflater#createView(Context, String, prefix, AttributeSet)
+ // onCreateView with Context should be called when there is no factory to inflate and should
+ // pass the LayoutInflater's context at the root and the parent's context other times.
+ // createView with Context should be called when there is a "." in the name.
+ @Test
+ public void testCreateViewWithContext() throws Throwable {
+ final Context context = mLayoutInflater.getContext();
+ CreateViewContextInflater inflater = new CreateViewContextInflater(context);
+ final ViewGroup container = (ViewGroup) inflater.inflate(R.layout.inflater_layout, null);
+
+ // The LinearLayout and TextViews inflate with onCreateView
+ assertEquals(9, inflater.onCreateViewCalls.size());
+ assertEquals(context, inflater.onCreateViewCalls.get(0)[0]);
+ assertNull(inflater.onCreateViewCalls.get(0)[1]);
+ assertEquals("LinearLayout", inflater.onCreateViewCalls.get(0)[2]);
+
+ Context parentContext = container.getContext();
+ // This should be a wrapper context since MethodTrackerInflater changes LinearLayout context
+ assertNotSame(context, parentContext);
+ for (int i = 1; i < 9; i++) {
+ Object[] params = inflater.onCreateViewCalls.get(i);
+ assertEquals(parentContext, params[0]);
+ assertEquals(container, params[1]);
+ assertEquals("TextView", params[2]);
+ }
+
+ // Also has android.view.ct.MockViewStub
+ assertEquals(9, container.getChildCount());
+ View mockViewStub = container.getChildAt(8);
+ assertEquals(parentContext, mockViewStub.getContext());
+ }
+
static class MockLayoutInflater extends LayoutInflater {
public MockLayoutInflater(Context c) {
@@ -434,6 +472,41 @@
}
}
+ /**
+ * Used to track calling of onCreateView protected method.
+ */
+ static class CreateViewContextInflater extends LayoutInflater {
+ public final List<Object[]> onCreateViewCalls = new ArrayList<>();
+
+ CreateViewContextInflater(Context context) {
+ super(context);
+ }
+
+ @Override
+ public LayoutInflater cloneInContext(Context newContext) {
+ return null;
+ }
+
+ @Override
+ public View onCreateView(Context viewContext, View parent, String name,
+ AttributeSet attrs) throws ClassNotFoundException {
+ onCreateViewCalls.add(new Object[] {viewContext, parent, name, attrs});
+ if ("LinearLayout".equals(name)) {
+ viewContext = new ContextWrapper(viewContext);
+ }
+ String prefix = null;
+ int dotIndex = name.lastIndexOf('.');
+ if (dotIndex >= 0) {
+ prefix = name.substring(0, dotIndex + 1);
+ name = name.substring(dotIndex + 1);
+ } else {
+ prefix = "android.widget.";
+ }
+
+ return createView(viewContext, name, prefix, attrs);
+ }
+ }
+
private XmlResourceParser getParser() {
XmlResourceParser parser = null;
ActivityInfo ai = null;
diff --git a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
index aa9dcf1..d8c293f 100644
--- a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
@@ -19,9 +19,11 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.TypedValue;
import android.view.ViewConfiguration;
import org.junit.Test;
@@ -65,7 +67,8 @@
@Test
public void testInstanceValues() {
- ViewConfiguration vc = ViewConfiguration.get(InstrumentationRegistry.getTargetContext());
+ Context context = InstrumentationRegistry.getTargetContext();
+ ViewConfiguration vc = ViewConfiguration.get(context);
assertNotNull(vc);
vc.getScaledDoubleTapSlop();
@@ -83,6 +86,30 @@
vc.getScaledTouchSlop();
vc.getScaledWindowTouchSlop();
vc.hasPermanentMenuKey();
+
+ float pixelsToMmRatio = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
+ context.getResources().getDisplayMetrics());
+
+ // Verify that the min scaling span size is reasonable.
+ float scaledMinScalingSpanMm = vc.getScaledMinScalingSpan() / pixelsToMmRatio;
+ assertTrue(scaledMinScalingSpanMm > 0);
+ assertTrue(scaledMinScalingSpanMm < 40.5); // 1.5 times the recommended size of 27mm
+ }
+
+ @Test
+ public void testExceptionsThrown() {
+ ViewConfiguration vc = new ViewConfiguration();
+ boolean correctExceptionThrown = false;
+ try {
+ vc.getScaledMinScalingSpan();
+ } catch (IllegalStateException e) {
+ if (e.getMessage().equals("Min scaling span cannot be determined when this "
+ + "method is called on a ViewConfiguration that was instantiated using a "
+ + "constructor with no Context parameter")) {
+ correctExceptionThrown = true;
+ }
+ }
+ assertTrue(correctExceptionThrown);
}
/**
diff --git a/tests/tests/view/src/android/view/cts/ViewStyleTest.java b/tests/tests/view/src/android/view/cts/ViewStyleTest.java
new file mode 100644
index 0000000..866e8b6
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/ViewStyleTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.assertEquals;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+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.support.test.uiautomator.UiDevice;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Map;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewStyleTest {
+
+ @Rule
+ public ActivityTestRule<Activity> mActivityRule =
+ new ActivityTestRule<>(Activity.class, true, false);
+
+ private static final String DISABLE_SHELL_COMMAND =
+ "settings delete global debug_view_attributes_application_package";
+
+ private static final String ENABLE_SHELL_COMMAND =
+ "settings put global debug_view_attributes_application_package android.view.cts";
+
+ private UiDevice mUiDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mUiDevice.executeShellCommand(ENABLE_SHELL_COMMAND);
+ mActivityRule.launchActivity(null);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mUiDevice.executeShellCommand(DISABLE_SHELL_COMMAND);
+ }
+
+ @Test
+ public void testGetExplicitStyle() {
+ Context context = InstrumentationRegistry.getTargetContext();
+ LayoutInflater inflater = LayoutInflater.from(context);
+ LinearLayout rootView = (LinearLayout) inflater.inflate(R.layout.view_style_layout, null);
+ View view1 = rootView.findViewById(R.id.view1);
+ assertEquals(R.style.ExplicitStyle1, view1.getExplicitStyle());
+
+ View view2 = rootView.findViewById(R.id.view2);
+ assertEquals(R.style.ExplicitStyle2, view2.getExplicitStyle());
+
+ View view3 = rootView.findViewById(R.id.view3);
+ assertEquals(Resources.ID_NULL, view3.getExplicitStyle());
+
+ View view4 = rootView.findViewById(R.id.view4);
+ assertEquals(android.R.style.TextAppearance_Material_Large, view4.getExplicitStyle());
+ }
+
+ @Test
+ public void testGetAttributeResolutionStack() {
+ LayoutInflater inflater = LayoutInflater.from(mActivityRule.getActivity());
+ LinearLayout rootView = (LinearLayout) inflater.inflate(R.layout.view_style_layout, null);
+ // View that has an explicit style ExplicitStyle1 set via style = ...
+ View view1 = rootView.findViewById(R.id.view1);
+ List<Integer> stackView1 = view1.getAttributeResolutionStack();
+ assertEquals(3, stackView1.size());
+ assertEquals(R.layout.view_style_layout, stackView1.get(0).intValue());
+ assertEquals(R.style.ExplicitStyle1, stackView1.get(1).intValue());
+ assertEquals(R.style.ParentOfExplicitStyle1, stackView1.get(2).intValue());
+
+ // Button that has the default style MyButtonStyle set in ViewStyleTestTheme Activity theme
+ // via android:buttonStyle
+ Button button1 = rootView.findViewById(R.id.button1);
+ List<Integer> stackButton1 = button1.getAttributeResolutionStack();
+ assertEquals(3, stackButton1.size());
+ assertEquals(R.layout.view_style_layout, stackButton1.get(0).intValue());
+ assertEquals(R.style.MyButtonStyle, stackButton1.get(1).intValue());
+ assertEquals(R.style.MyButtonStyleParent, stackButton1.get(2).intValue());
+
+ // Button that has the default style MyButtonStyle set in ViewStyleTestTheme Activity theme
+ // via android:buttonStyle and has an explicit style ExplicitStyle1 set via style = ...
+ Button button2 = rootView.findViewById(R.id.button2);
+ List<Integer> stackButton2 = button2.getAttributeResolutionStack();
+ assertEquals(5, stackButton2.size());
+ assertEquals(R.layout.view_style_layout, stackButton2.get(0).intValue());
+ assertEquals(R.style.ExplicitStyle1, stackButton2.get(1).intValue());
+ assertEquals(R.style.ParentOfExplicitStyle1, stackButton2.get(2).intValue());
+ assertEquals(R.style.MyButtonStyle, stackButton2.get(3).intValue());
+ assertEquals(R.style.MyButtonStyleParent, stackButton2.get(4).intValue());
+ }
+
+ @Test
+ public void testGetAttributeSourceResourceMap() {
+ LayoutInflater inflater = LayoutInflater.from(mActivityRule.getActivity());
+ LinearLayout rootView = (LinearLayout) inflater.inflate(R.layout.view_style_layout, null);
+ // View that has an explicit style ExplicitStyle1 set via style = ...
+ View view1 = rootView.findViewById(R.id.view1);
+ Map<Integer, Integer> attributeMapView1 = view1.getAttributeSourceResourceMap();
+ assertEquals(9, attributeMapView1.size());
+ assertEquals(R.style.ExplicitStyle1,
+ (attributeMapView1.get(android.R.attr.padding)).intValue());
+ assertEquals(R.style.ParentOfExplicitStyle1,
+ (attributeMapView1.get(android.R.attr.paddingLeft)).intValue());
+ assertEquals(R.layout.view_style_layout,
+ (attributeMapView1.get(android.R.attr.paddingTop)).intValue());
+ }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java b/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java
index 5435cf8..a78f219 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ChromeClient.java
@@ -18,33 +18,25 @@
import android.webkit.ConsoleMessage;
import android.webkit.cts.WebViewSyncLoader.WaitForProgressClient;
+import com.google.common.util.concurrent.SettableFuture;
+
// A chrome client for listening webview chrome events.
class ChromeClient extends WaitForProgressClient {
-
- private boolean mIsMessageLevelAvailable;
- private ConsoleMessage.MessageLevel mMessageLevel;
+ private final SettableFuture<ConsoleMessage.MessageLevel> mMessageLevel =
+ SettableFuture.create();
public ChromeClient(WebViewOnUiThread onUiThread) {
super(onUiThread);
}
@Override
- public synchronized boolean onConsoleMessage(ConsoleMessage message) {
- mMessageLevel = message.messageLevel();
- mIsMessageLevelAvailable = true;
- notify();
+ public boolean onConsoleMessage(ConsoleMessage message) {
+ mMessageLevel.set(message.messageLevel());
// return false for default handling; i.e. printing the message.
return false;
}
- public synchronized ConsoleMessage.MessageLevel getMessageLevel(int timeout) {
- for(; timeout > 0; timeout -= 1000) {
- if( mIsMessageLevelAvailable ) break;
- try {
- wait(1000);
- } catch (InterruptedException e) {
- }
- }
- return mMessageLevel;
+ public ConsoleMessage.MessageLevel getMessageLevel() {
+ return WebkitUtils.waitForFuture(mMessageLevel);
}
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index eac21a9..d939ac5 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -49,6 +49,9 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
/**
* Tests for {@link android.webkit.WebSettings}
*/
@@ -214,10 +217,14 @@
assertEquals(TestHtmlConstants.WEBPAGE_NOT_AVAILABLE_TITLE, mOnUiThread.getTitle());
}
- public void testAccessCacheMode() throws Throwable {
+ public void testAccessCacheMode_defaultValue() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
+ assertEquals(WebSettings.LOAD_DEFAULT, mSettings.getCacheMode());
+ }
+
+ private void openIconDatabase() throws InterruptedException {
WebkitUtils.onMainThreadSync(() -> {
// getInstance must run on the UI thread
WebIconDatabase iconDb = WebIconDatabase.getInstance();
@@ -226,64 +233,81 @@
});
getInstrumentation().waitForIdleSync();
Thread.sleep(100); // Wait for open to be received on the icon db thread.
- assertEquals(WebSettings.LOAD_DEFAULT, mSettings.getCacheMode());
+ }
+
+ public void testAccessCacheMode_cacheElseNetwork() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ openIconDatabase();
+ final IconListenerClient iconListener = new IconListenerClient();
+ mOnUiThread.setWebChromeClient(iconListener);
+ startWebServer();
mSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
assertEquals(WebSettings.LOAD_CACHE_ELSE_NETWORK, mSettings.getCacheMode());
+ int initialRequestCount = mWebServer.getRequestCount();
+ loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ iconListener.waitForNextIcon();
+ int requestCountAfterFirstLoad = mWebServer.getRequestCount();
+ assertTrue("Must fetch non-cached resource from server",
+ requestCountAfterFirstLoad > initialRequestCount);
+ iconListener.drainIconQueue();
+ loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ iconListener.waitForNextIcon();
+ int requestCountAfterSecondLoad = mWebServer.getRequestCount();
+ assertEquals("Expected to use cache instead of re-fetching resource",
+ requestCountAfterSecondLoad, requestCountAfterFirstLoad);
+ }
+
+ public void testAccessCacheMode_noCache() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ openIconDatabase();
final IconListenerClient iconListener = new IconListenerClient();
mOnUiThread.setWebChromeClient(iconListener);
- loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- new PollingCheck(WEBVIEW_TIMEOUT) {
- @Override
- protected boolean check() {
- return iconListener.mReceivedIcon;
- }
- }.run();
- int firstFetch = mWebServer.getRequestCount();
- iconListener.mReceivedIcon = false;
- loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- new PollingCheck(WEBVIEW_TIMEOUT) {
- @Override
- protected boolean check() {
- return iconListener.mReceivedIcon;
- }
- }.run();
- assertEquals(firstFetch, mWebServer.getRequestCount());
+ startWebServer();
mSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
assertEquals(WebSettings.LOAD_NO_CACHE, mSettings.getCacheMode());
- iconListener.mReceivedIcon = false;
+ int initialRequestCount = mWebServer.getRequestCount();
loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- new PollingCheck(WEBVIEW_TIMEOUT) {
- @Override
- protected boolean check() {
- return iconListener.mReceivedIcon;
- }
- }.run();
- int secondFetch = mWebServer.getRequestCount();
- iconListener.mReceivedIcon = false;
+ iconListener.waitForNextIcon();
+ int requestCountAfterFirstLoad = mWebServer.getRequestCount();
+ assertTrue("Must fetch non-cached resource from server",
+ requestCountAfterFirstLoad > initialRequestCount);
+ iconListener.drainIconQueue();
loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- new PollingCheck(WEBVIEW_TIMEOUT) {
- @Override
- protected boolean check() {
- return iconListener.mReceivedIcon;
- }
- }.run();
- int thirdFetch = mWebServer.getRequestCount();
- assertTrue(firstFetch < secondFetch);
- assertTrue(secondFetch < thirdFetch);
+ iconListener.waitForNextIcon();
+ int requestCountAfterSecondLoad = mWebServer.getRequestCount();
+ assertTrue("Expected to re-fetch resource instead of caching",
+ requestCountAfterSecondLoad > requestCountAfterFirstLoad);
+ }
+
+ public void testAccessCacheMode_cacheOnly() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ openIconDatabase();
+ final IconListenerClient iconListener = new IconListenerClient();
+ mOnUiThread.setWebChromeClient(iconListener);
+ startWebServer();
+
+ // As a precondition, get the icon in the cache.
+ mSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
+ loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ iconListener.waitForNextIcon();
mSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
assertEquals(WebSettings.LOAD_CACHE_ONLY, mSettings.getCacheMode());
- iconListener.mReceivedIcon = false;
+ iconListener.drainIconQueue();
+ int initialRequestCount = mWebServer.getRequestCount();
loadAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- new PollingCheck(WEBVIEW_TIMEOUT) {
- @Override
- protected boolean check() {
- return iconListener.mReceivedIcon;
- }
- }.run();
- assertEquals(thirdFetch, mWebServer.getRequestCount());
+ iconListener.waitForNextIcon();
+ int requestCountAfterFirstLoad = mWebServer.getRequestCount();
+ assertEquals("Expected to use cache instead of fetching resource",
+ requestCountAfterFirstLoad, initialRequestCount);
}
public void testAccessCursiveFontFamily() throws Exception {
@@ -754,29 +778,65 @@
}
}
- public void testLoadsImagesAutomatically() throws Throwable {
+ public void testLoadsImagesAutomatically_default() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
assertTrue(mSettings.getLoadsImagesAutomatically());
+ }
+ public void testLoadsImagesAutomatically_httpImagesLoaded() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
startWebServer();
mSettings.setJavaScriptEnabled(true);
+ mSettings.setLoadsImagesAutomatically(true);
- // Check that by default network and data url images are loaded.
mOnUiThread.loadDataAndWaitForCompletion(getNetworkImageHtml(), "text/html", null);
assertEquals(NETWORK_IMAGE_HEIGHT, mOnUiThread.getTitle());
+ }
+
+ public void testLoadsImagesAutomatically_dataUriImagesLoaded() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ startWebServer();
+ mSettings.setJavaScriptEnabled(true);
+ mSettings.setLoadsImagesAutomatically(true);
+
mOnUiThread.loadDataAndWaitForCompletion(DATA_URL_IMAGE_HTML, "text/html", null);
assertEquals(DATA_URL_IMAGE_HEIGHT, mOnUiThread.getTitle());
+ }
- // Check that with auto-loading turned off no images are loaded.
- // Also check that images are loaded automatically once we enable the setting,
- // without reloading the page.
+ public void testLoadsImagesAutomatically_blockLoadingImages() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ startWebServer();
+ mSettings.setJavaScriptEnabled(true);
mSettings.setLoadsImagesAutomatically(false);
- mOnUiThread.clearCache(true);
+
+ mOnUiThread.clearCache(true); // in case of side-effects from other tests
mOnUiThread.loadDataAndWaitForCompletion(getNetworkImageHtml(), "text/html", null);
assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
- mSettings.setLoadsImagesAutomatically(true);
+
+ mOnUiThread.loadDataAndWaitForCompletion(DATA_URL_IMAGE_HTML, "text/html", null);
+ assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
+ }
+
+ public void testLoadsImagesAutomatically_loadImagesWithoutReload() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ startWebServer();
+ mSettings.setJavaScriptEnabled(true);
+ mSettings.setLoadsImagesAutomatically(false);
+
+ mOnUiThread.clearCache(true); // in case of side-effects from other tests
+ mOnUiThread.loadDataAndWaitForCompletion(getNetworkImageHtml(), "text/html", null);
+ assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
+ mSettings.setLoadsImagesAutomatically(true); // load images, without calling #reload()
waitForNonEmptyImage();
assertEquals(NETWORK_IMAGE_HEIGHT, mOnUiThread.getTitle());
@@ -784,7 +844,7 @@
mOnUiThread.clearCache(true);
mOnUiThread.loadDataAndWaitForCompletion(DATA_URL_IMAGE_HTML, "text/html", null);
assertEquals(EMPTY_IMAGE_HEIGHT, mOnUiThread.getTitle());
- mSettings.setLoadsImagesAutomatically(true);
+ mSettings.setLoadsImagesAutomatically(true); // load images, without calling #reload()
waitForNonEmptyImage();
assertEquals(DATA_URL_IMAGE_HEIGHT, mOnUiThread.getTitle());
}
@@ -913,7 +973,7 @@
mOnUiThread.loadUrlAndWaitForCompletion(url);
String iframeUrl = TestHtmlConstants.getFileUrl(TestHtmlConstants.HELLO_WORLD_URL);
assertFalse(iframeUrl.equals(mOnUiThread.getTitle()));
- assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel(10000));
+ assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel());
}
// Verify that enabling file access from file URLs enable XmlHttpRequest (XHR) across files
@@ -933,7 +993,7 @@
final ChromeClient webChromeClient = new ChromeClient(mOnUiThread);
mOnUiThread.setWebChromeClient(webChromeClient);
verifyFileXHR(false);
- assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel(10000));
+ assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel());
}
// verify XHR across files matches the allowFileAccessFromFileURLs setting
@@ -1115,7 +1175,7 @@
}
private class IconListenerClient extends WaitForProgressClient {
- public boolean mReceivedIcon;
+ private final BlockingQueue<Bitmap> mReceivedIconQueue = new LinkedBlockingQueue<>();
public IconListenerClient() {
super(mOnUiThread);
@@ -1123,7 +1183,20 @@
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
- mReceivedIcon = true;
+ mReceivedIconQueue.add(icon);
+ }
+
+ /**
+ * Exposed as a precaution, in case for some reason we get multiple calls to
+ * {@link #onReceivedIcon}.
+ */
+ public void drainIconQueue() {
+ while (mReceivedIconQueue.poll() != null) {}
+ }
+
+ public void waitForNextIcon() {
+ // TODO(ntfschr): consider exposing the Bitmap, if we want to make assertions.
+ WebkitUtils.waitForNextQueueElement(mReceivedIconQueue);
}
}
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index bbaac70..4611973 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -124,6 +124,10 @@
private static final String X_REQUESTED_WITH = "X-Requested-With";
private static final String PRINTER_TEST_FILE = "print.pdf";
private static final String PDF_PREAMBLE = "%PDF-1";
+ // Snippet of HTML that will prevent favicon requests to the test server.
+ private static final String HTML_HEADER =
+ "<html><head><link rel=\"shortcut icon\" href=\"%23\" /></head>";
+ private static final String SIMPLE_HTML = "<html><body>simple html</body></html>";
/**
* This is the minimum number of milliseconds to wait for scrolling to
@@ -147,11 +151,6 @@
*/
private static final long SCROLL_WAIT_INTERVAL_MS = 200;
- /**
- * Epsilon used in page scale value comparisons.
- */
- private static final float PAGE_SCALE_EPSILON = 0.0001f;
-
private WebView mWebView;
private CtsTestServer mWebServer;
private WebViewOnUiThread mOnUiThread;
@@ -296,122 +295,6 @@
assertNull(WebView.findAddress("This is not an address: no town, no state, no zip."));
}
- @SuppressWarnings("deprecation")
- @UiThreadTest
- public void testGetZoomControls() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- WebSettings settings = mWebView.getSettings();
- assertTrue(settings.supportZoom());
- View zoomControls = mWebView.getZoomControls();
- assertNotNull(zoomControls);
-
- // disable zoom support
- settings.setSupportZoom(false);
- assertFalse(settings.supportZoom());
- assertNull(mWebView.getZoomControls());
- }
-
- @UiThreadTest
- public void testInvokeZoomPicker() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- WebSettings settings = mWebView.getSettings();
- assertTrue(settings.supportZoom());
- startWebServer(false);
- String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- mOnUiThread.loadUrlAndWaitForCompletion(url);
- mWebView.invokeZoomPicker();
- }
-
- public void testZoom() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- // Pinch zoom is not supported in wrap_content layouts.
- mOnUiThread.setLayoutHeightToMatchParent();
-
- final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
- mOnUiThread.setWebViewClient(webViewClient);
-
- mWebServer = new CtsTestServer(getActivity());
- mOnUiThread.loadUrlAndWaitForCompletion(
- mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
- pollingCheckForCanZoomIn();
-
- WebSettings settings = mOnUiThread.getSettings();
- settings.setSupportZoom(false);
- assertFalse(settings.supportZoom());
- float currScale = mOnUiThread.getScale();
- float previousScale = currScale;
-
- // can zoom in or out although zoom support is disabled in web settings
- assertTrue(mOnUiThread.zoomIn());
- currScale = webViewClient.expectZoomIn(currScale);
-
- assertTrue(mOnUiThread.zoomOut());
- currScale = webViewClient.expectZoomOut(currScale);
-
- mOnUiThread.zoomBy(1.25f); // zoom in
- currScale = webViewClient.expectZoomBy(currScale, 1.25f);
-
- mOnUiThread.zoomBy(0.8f); // zoom out
- currScale = webViewClient.expectZoomBy(currScale, 0.8f);
-
- // enable zoom support
- settings.setSupportZoom(true);
- assertTrue(settings.supportZoom());
-
- // Zoom in until maximum scale, in default increments.
- while (mOnUiThread.zoomIn()) {
- currScale = webViewClient.expectZoomIn(currScale);
- }
-
- assertFalse(mOnUiThread.zoomIn());
- assertNoScaleChange(webViewClient, currScale);
-
- // Zoom out until minimum scale, in default increments.
- while (mOnUiThread.zoomOut()) {
- currScale = webViewClient.expectZoomOut(currScale);
- }
-
- assertFalse(mOnUiThread.zoomOut());
- assertNoScaleChange(webViewClient, currScale);
-
- // Zoom in until maximum scale, in specified increments designed so that the last zoom will
- // be less than expected.
- while (mOnUiThread.canZoomIn()) {
- mOnUiThread.zoomBy(1.7f);
- currScale = webViewClient.expectZoomBy(currScale, 1.7f);
- }
-
- // At this point, zooming in should do nothing.
- mOnUiThread.zoomBy(1.7f);
- assertNoScaleChange(webViewClient, currScale);
-
- // Zoom out until minimum scale, in specified increments designed so that the last zoom will
- // be less than requested.
- while (mOnUiThread.canZoomOut()) {
- mOnUiThread.zoomBy(0.7f);
- currScale = webViewClient.expectZoomBy(currScale, 0.7f);
- }
-
- // At this point, zooming out should do nothing.
- mOnUiThread.zoomBy(0.7f);
- assertNoScaleChange(webViewClient, currScale);
- }
-
- private void assertNoScaleChange(ScaleChangedWebViewClient webViewClient, float currScale) throws InterruptedException {
- // We sleep to assert to the best of our ability
- // that a scale change does *not* happen.
- Thread.sleep(500);
- assertFalse(webViewClient.onScaleChangedCalled());
- assertEquals(currScale, mOnUiThread.getScale());
- }
-
@UiThreadTest
public void testScrollBarOverlay() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -1233,88 +1116,130 @@
startWebServer(false);
final ChromeClient webChromeClient = new ChromeClient(mOnUiThread);
final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- WebkitUtils.onMainThreadSync(() -> {
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.setWebChromeClient(webChromeClient);
- mOnUiThread.loadDataAndWaitForCompletion(
- "<html><head></head><body onload=\"" +
- "document.title = " +
- "document.getElementById('frame').contentWindow.location.href;" +
- "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
- "text/html", null);
- });
- assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel(10000));
+ mOnUiThread.getSettings().setJavaScriptEnabled(true);
+ mOnUiThread.setWebChromeClient(webChromeClient);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><head></head><body onload=\"" +
+ "document.title = " +
+ "document.getElementById('frame').contentWindow.location.href;" +
+ "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
+ "text/html", null);
+ assertEquals(ConsoleMessage.MessageLevel.ERROR, webChromeClient.getMessageLevel());
}
- @UiThreadTest
- public void testLoadDataWithBaseUrl() throws Throwable {
+ public void testLoadDataWithBaseUrl_resolvesRelativeToBaseUrl() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
- assertNull(mWebView.getUrl());
+ assertNull(mOnUiThread.getUrl());
String imgUrl = TestHtmlConstants.SMALL_IMG_URL; // relative
- // Snippet of HTML that will prevent favicon requests to the test server.
- final String HTML_HEADER = "<html><head><link rel=\"shortcut icon\" href=\"%23\" /></head>";
// Trying to resolve a relative URL against a data URL without a base URL
// will fail and we won't make a request to the test web server.
// By using the test web server as the base URL we expect to see a request
// for the relative URL in the test server.
startWebServer(false);
- String baseUrl = mWebServer.getAssetUrl("foo.html");
- String historyUrl = "http://www.example.com/";
+ final String baseUrl = mWebServer.getAssetUrl("foo.html");
mWebServer.resetRequestState();
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
HTML_HEADER + "<body><img src=\"" + imgUrl + "\"/></body></html>",
- "text/html", "UTF-8", historyUrl);
+ "text/html", "UTF-8", null);
// Verify that the resource request makes it to the server.
assertTrue(mWebServer.wasResourceRequested(imgUrl));
- assertEquals(historyUrl, mWebView.getUrl());
+ }
+ public void testLoadDataWithBaseUrl_historyUrl() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ final String baseUrl = "http://www.baseurl.com/";
+ final String historyUrl = "http://www.example.com/";
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
+ SIMPLE_HTML,
+ "text/html", "UTF-8", historyUrl);
+ assertEquals(historyUrl, mOnUiThread.getUrl());
+ }
+
+ public void testLoadDataWithBaseUrl_nullHistoryUrlShowsAsAboutBlank() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
// Check that reported URL is "about:blank" when supplied history URL
// is null.
- imgUrl = TestHtmlConstants.LARGE_IMG_URL;
+ final String baseUrl = "http://www.baseurl.com/";
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
- HTML_HEADER + "<body><img src=\"" + imgUrl + "\"/></body></html>",
+ SIMPLE_HTML,
"text/html", "UTF-8", null);
- assertTrue(mWebServer.wasResourceRequested(imgUrl));
- assertEquals("about:blank", mWebView.getUrl());
+ assertEquals("about:blank", mOnUiThread.getUrl());
+ }
+ public void testLoadDataWithBaseUrl_javascriptCanAccessOrigin() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
// Test that JavaScript can access content from the same origin as the base URL.
- mWebView.getSettings().setJavaScriptEnabled(true);
+ mOnUiThread.getSettings().setJavaScriptEnabled(true);
+ startWebServer(false);
+ final String baseUrl = mWebServer.getAssetUrl("foo.html");
final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
HTML_HEADER + "<body onload=\"" +
"document.title = document.getElementById('frame').contentWindow.location.href;" +
"\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
"text/html", "UTF-8", null);
- assertEquals(crossOriginUrl, mWebView.getTitle());
+ assertEquals(crossOriginUrl, mOnUiThread.getTitle());
+ }
+ public void testLoadDataWithBaseUrl_dataBaseUrlIgnoresHistoryUrl() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
// Check that when the base URL uses the 'data' scheme, a 'data' scheme URL is used and the
// history URL is ignored.
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("data:foo",
- HTML_HEADER + "<body>bar</body></html>", "text/html", "UTF-8",
- historyUrl);
- assertTrue("URL: " + mWebView.getUrl(), mWebView.getUrl().indexOf("data:text/html") == 0);
- assertTrue("URL: " + mWebView.getUrl(), mWebView.getUrl().indexOf("bar") > 0);
+ final String baseUrl = "data:foo";
+ final String historyUrl = "http://www.example.com/";
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
+ SIMPLE_HTML,
+ "text/html", "UTF-8", historyUrl);
+ final String currentUrl = mOnUiThread.getUrl();
+ assertEquals("Current URL (" + currentUrl + ") should be a data URI", 0,
+ mOnUiThread.getUrl().indexOf("data:text/html"));
+ assertTrue("Current URL (" + currentUrl + ") should contain the simple HTML we loaded",
+ mOnUiThread.getUrl().indexOf("simple html") > 0);
+ }
+
+ public void testLoadDataWithBaseUrl_unencodedContentHttpBaseUrl() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
// Check that when a non-data: base URL is used, we treat the String to load as
// a raw string and just dump it into the WebView, i.e. not decoding any URL entities.
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("http://www.foo.com",
HTML_HEADER + "<title>Hello World%21</title><body>bar</body></html>",
"text/html", "UTF-8", null);
- assertEquals("Hello World%21", mWebView.getTitle());
+ assertEquals("Hello World%21", mOnUiThread.getTitle());
+ }
+ public void testLoadDataWithBaseUrl_urlEncodedContentDataBaseUrl() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
// Check that when a data: base URL is used, we treat the String to load as a data: URL
// and run load steps such as decoding URL entities (i.e., contrary to the test case
// above.)
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("data:foo",
HTML_HEADER + "<title>Hello World%21</title></html>", "text/html", "UTF-8", null);
- assertEquals("Hello World!", mWebView.getTitle());
+ assertEquals("Hello World!", mOnUiThread.getTitle());
+ }
- // Check the method is null input safe.
+ public void testLoadDataWithBaseUrl_nullSafe() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(null, null, null, null, null);
- assertEquals("about:blank", mWebView.getUrl());
+ assertEquals("about:blank", mOnUiThread.getUrl());
}
private void deleteIfExists(File file) throws IOException {
@@ -1408,15 +1333,15 @@
private static class WaitForFindResultsListener
implements WebView.FindListener {
private final SettableFuture<Integer> mFuture;
- private final WebViewOnUiThread mWebViewOnUiThread;
+ private final WebView mWebView;
private final int mMatchesWanted;
private final String mStringWanted;
private final boolean mRetry;
public WaitForFindResultsListener(
- WebViewOnUiThread wv, String wanted, int matches, boolean retry) {
+ WebView wv, String wanted, int matches, boolean retry) {
mFuture = SettableFuture.create();
- mWebViewOnUiThread = wv;
+ mWebView = wv;
mMatchesWanted = matches;
mStringWanted = wanted;
mRetry = retry;
@@ -1429,10 +1354,16 @@
@Override
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
boolean isDoneCounting) {
+ try {
+ assertEquals("WebView.FindListener callbacks should occur on the UI thread",
+ Looper.myLooper(), Looper.getMainLooper());
+ } catch (Throwable t) {
+ mFuture.setException(t);
+ }
if (isDoneCounting) {
//If mRetry set to true and matches aren't equal, call findAll again
if (mRetry && numberOfMatches != mMatchesWanted) {
- mWebViewOnUiThread.findAll(mStringWanted);
+ mWebView.findAll(mStringWanted);
}
else {
mFuture.set(numberOfMatches);
@@ -1457,7 +1388,7 @@
mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+ "</body></html>", "text/html", null);
- WaitForFindResultsListener l = new WaitForFindResultsListener(mOnUiThread, "find", 2, true);
+ WaitForFindResultsListener l = new WaitForFindResultsListener(mWebView, "find", 2, true);
mOnUiThread.setFindListener(l);
mOnUiThread.findAll("find");
assertEquals(2, (int)WebkitUtils.waitForFuture(l.future()));
@@ -1477,7 +1408,7 @@
"Find all instances of a word on the page and highlight them.</p>";
mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p + p + "</body></html>", "text/html", null);
- WaitForFindResultsListener l = new WaitForFindResultsListener(mOnUiThread, "all", 2, true);
+ WaitForFindResultsListener l = new WaitForFindResultsListener(mWebView, "all", 2, true);
mOnUiThread.setFindListener(l);
// highlight all the strings found and wait for all the matches to be found
@@ -2113,47 +2044,6 @@
assertEquals(url3, copyListAfterRestore.getItemAtIndex(2).getUrl());
}
- public void testSetWebViewClient() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
- mOnUiThread.setWebViewClient(webViewClient);
- startWebServer(false);
-
- assertFalse(webViewClient.onScaleChangedCalled());
- String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- mOnUiThread.loadUrlAndWaitForCompletion(url1);
- pollingCheckForCanZoomIn();
-
- assertTrue(mOnUiThread.zoomIn());
- webViewClient.waitForNextScaleChange();
- }
-
- public void testScaleChangeCallbackMatchesGetScale() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- // wrap_parent layout causes extra onScaleChanged ecallbacks, so set to match_parent to
- // suppress them.
- mOnUiThread.setLayoutHeightToMatchParent();
- final ScaleChangedWebViewClient webViewClient = new ScaleChangedWebViewClient();
- mOnUiThread.setWebViewClient(webViewClient);
- startWebServer(false);
-
- assertFalse(webViewClient.onScaleChangedCalled());
- String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- mOnUiThread.loadUrlAndWaitForCompletion(url1);
- pollingCheckForCanZoomIn();
-
- assertFalse(webViewClient.onScaleChangedCalled());
- assertTrue(mOnUiThread.zoomIn());
- ScaleChangedState state = webViewClient.waitForNextScaleChange();
- assertEquals(
- "Expected onScaleChanged arg 2 (new scale) to equal view.getScale()",
- state.mNewScale, mOnUiThread.getScale());
- }
-
public void testRequestChildRectangleOnScreen() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
@@ -2901,103 +2791,6 @@
}
}
- private void pollingCheckForCanZoomIn() {
- new PollingCheck(TEST_TIMEOUT) {
- @Override
- protected boolean check() {
- return mOnUiThread.canZoomIn();
- }
- }.run();
- }
-
- static class ScaleChangedState {
- public float mOldScale;
- public float mNewScale;
- public boolean mCanZoomIn;
- public boolean mCanZoomOut;
-
- ScaleChangedState(WebView view, float oldScale, float newScale) {
- mOldScale = oldScale;
- mNewScale = newScale;
- mCanZoomIn = view.canZoomIn();
- mCanZoomOut = view.canZoomOut();
- }
- }
-
- final class ScaleChangedWebViewClient extends WaitForLoadedClient {
- private BlockingQueue<ScaleChangedState> mCallQueue;
-
- public ScaleChangedWebViewClient() {
- super(mOnUiThread);
- mCallQueue = new LinkedBlockingQueue<>();
- }
-
- @Override
- public void onScaleChanged(WebView view, float oldScale, float newScale) {
- super.onScaleChanged(view, oldScale, newScale);
- mCallQueue.add(new ScaleChangedState(view, oldScale, newScale));
- }
-
- public float expectZoomBy(float currentScale, float scaleAmount) {
- assertTrue(scaleAmount != 1.0f);
-
- float nextScale = currentScale * scaleAmount;
- ScaleChangedState state = waitForNextScaleChange();
- assertEquals(currentScale, state.mOldScale);
-
- // Check that we zoomed in the expected direction wrt. the current scale.
- if (scaleAmount > 1.0f) {
- assertTrue(
- "Expected new scale > current scale when zooming in",
- state.mNewScale > currentScale);
- } else {
- assertTrue(
- "Expected new scale < current scale when zooming out",
- state.mNewScale < currentScale);
- }
-
- // If we hit the zoom limit, then the new scale should be between the old scale
- // and the expected new scale. Otherwise it should equal the expected new scale.
- if (Math.abs(nextScale - state.mNewScale) > PAGE_SCALE_EPSILON) {
- if (scaleAmount > 1.0f) {
- assertFalse(state.mCanZoomIn);
- assertTrue(
- "Expected new scale <= requested scale when zooming in past limit",
- state.mNewScale <= nextScale);
- } else {
- assertFalse(state.mCanZoomOut);
- assertTrue(
- "Expected new scale >= requested scale when zooming out past limit",
- state.mNewScale >= nextScale);
- }
- }
-
- return state.mNewScale;
- }
-
- public float expectZoomOut(float currentScale) {
- ScaleChangedState state = waitForNextScaleChange();
- assertEquals(currentScale, state.mOldScale);
- assertTrue(state.mNewScale < currentScale);
- return state.mNewScale;
- }
-
- public float expectZoomIn(float currentScale) {
- ScaleChangedState state = waitForNextScaleChange();
- assertEquals(currentScale, state.mOldScale);
- assertTrue(state.mNewScale > currentScale);
- return state.mNewScale;
- }
-
- public ScaleChangedState waitForNextScaleChange() {
- return WebkitUtils.waitForNextQueueElement(mCallQueue);
- }
-
- public boolean onScaleChangedCalled() {
- return mCallQueue.size() > 0;
- }
- }
-
/**
* This should remain functionally equivalent to
* androidx.webkit.WebViewCompatTest#testGetSafeBrowsingPrivacyPolicyUrl. Modifications to this
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
new file mode 100644
index 0000000..93e2cd5
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.webkit.cts;
+
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import android.test.ActivityInstrumentationTestCase2;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Test WebView zooming behaviour
+ */
+public class WebViewZoomTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
+ private WebView mWebView;
+ private WebViewOnUiThread mOnUiThread;
+ private ScaleChangedWebViewClient mWebViewClient;
+ private CtsTestServer mWebServer;
+
+ /**
+ * Epsilon used in page scale value comparisons.
+ */
+ private static final float PAGE_SCALE_EPSILON = 0.0001f;
+
+ public WebViewZoomTest() {
+ super("com.android.cts.webkit", WebViewCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final WebViewCtsActivity activity = getActivity();
+ mWebView = activity.getWebView();
+ if (mWebView == null)
+ return;
+
+ new PollingCheck() {
+ @Override
+ protected boolean check() {
+ return activity.hasWindowFocus();
+ }
+ }.run();
+ mOnUiThread = new WebViewOnUiThread(mWebView);
+ mWebViewClient = new ScaleChangedWebViewClient();
+ mOnUiThread.setWebViewClient(mWebViewClient);
+
+ // Pinch zoom is not supported in wrap_content layouts.
+ mOnUiThread.setLayoutHeightToMatchParent();
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mOnUiThread != null) {
+ mOnUiThread.cleanUp();
+ }
+ if (mWebServer != null) {
+ stopWebServer();
+ }
+ super.tearDown();
+ }
+
+ private void startWebServer(boolean secure) throws Exception {
+ assertNull(mWebServer);
+ mWebServer = new CtsTestServer(getActivity(), secure);
+ }
+
+ private void stopWebServer() throws Exception {
+ assertNotNull(mWebServer);
+ ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ ThreadPolicy tmpPolicy = new ThreadPolicy.Builder(oldPolicy)
+ .permitNetwork()
+ .build();
+ StrictMode.setThreadPolicy(tmpPolicy);
+ mWebServer.shutdown();
+ mWebServer = null;
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+
+ private void setUpPage() throws Exception {
+ assertFalse(mWebViewClient.onScaleChangedCalled());
+ startWebServer(false);
+ mOnUiThread.loadUrlAndWaitForCompletion(
+ mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
+ pollingCheckForCanZoomIn();
+ }
+
+ public void testZoomIn() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
+ setUpPage();
+
+ assertTrue(mOnUiThread.zoomIn());
+ mWebViewClient.waitForNextScaleChange();
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetZoomControls() {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ WebSettings settings = mOnUiThread.getSettings();
+ assertTrue(settings.supportZoom());
+ assertNotNull(
+ "Should be able to get zoom controls when zoom is enabled",
+ WebkitUtils.onMainThreadSync(() -> { return mWebView.getZoomControls(); }));
+
+ // disable zoom support
+ settings.setSupportZoom(false);
+ assertFalse(settings.supportZoom());
+ assertNull(
+ "Should not be able to get zoom controls when zoom is disabled",
+ WebkitUtils.onMainThreadSync(() -> { return mWebView.getZoomControls(); }));
+ }
+
+ public void testInvokeZoomPicker() throws Exception {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ WebSettings settings = mOnUiThread.getSettings();
+ assertTrue(settings.supportZoom());
+ setUpPage();
+ WebkitUtils.onMainThreadSync(() -> mWebView.invokeZoomPicker());
+ }
+
+ public void testZoom_canNotZoomInPastMaximum() {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ float currScale = mOnUiThread.getScale();
+ // Zoom in until maximum scale, in default increments.
+ while (mOnUiThread.zoomIn()) {
+ currScale = mWebViewClient.expectZoomIn(currScale);
+ }
+
+ assertFalse(mOnUiThread.zoomIn());
+ assertNoScaleChange(currScale);
+ }
+
+ public void testZoom_canNotZoomOutPastMinimum() {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ float currScale = mOnUiThread.getScale();
+ // Zoom in until maximum scale, in default increments.
+ while (mOnUiThread.zoomOut()) {
+ currScale = mWebViewClient.expectZoomOut(currScale);
+ }
+
+ assertFalse(mOnUiThread.zoomOut());
+ assertNoScaleChange(currScale);
+ }
+
+ public void testCanZoomWhileZoomSupportedFalse() throws Throwable {
+ // setZoomSupported disables user controls, but not zooming via API
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
+ setUpPage();
+
+ WebSettings settings = mOnUiThread.getSettings();
+ settings.setSupportZoom(false);
+ assertFalse(settings.supportZoom());
+
+ float currScale = mOnUiThread.getScale();
+
+ // can zoom in or out although zoom support is disabled in web settings
+ assertTrue(mOnUiThread.zoomIn());
+ currScale = mWebViewClient.expectZoomIn(currScale);
+
+ assertTrue(mOnUiThread.zoomOut());
+ currScale = mWebViewClient.expectZoomOut(currScale);
+ }
+
+ public void testZoomByPowerOfTwoIncrements() throws Throwable {
+ // setZoomSupported disables user controls, but not zooming via API
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
+ setUpPage();
+ float currScale = mOnUiThread.getScale();
+
+ mOnUiThread.zoomBy(1.25f); // zoom in
+ currScale = mWebViewClient.expectZoomBy(currScale, 1.25f);
+
+ mOnUiThread.zoomBy(0.75f); // zoom out
+ currScale = mWebViewClient.expectZoomBy(currScale, 0.75f);
+ }
+
+ public void testZoomByNonPowerOfTwoIncrements() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
+ setUpPage();
+
+ float currScale = mOnUiThread.getScale();
+
+ // Zoom in until maximum scale, in specified increments designed so that the last zoom will
+ // be less than expected.
+ while (mOnUiThread.canZoomIn()) {
+ mOnUiThread.zoomBy(1.7f);
+ currScale = mWebViewClient.expectZoomBy(currScale, 1.7f);
+ }
+
+ // At this point, zooming in should do nothing.
+ mOnUiThread.zoomBy(1.7f);
+ assertNoScaleChange(currScale);
+
+ // Zoom out until minimum scale, in specified increments designed so that the last zoom will
+ // be less than requested.
+ while (mOnUiThread.canZoomOut()) {
+ mOnUiThread.zoomBy(0.7f);
+ currScale = mWebViewClient.expectZoomBy(currScale, 0.7f);
+ }
+
+ // At this point, zooming out should do nothing.
+ mOnUiThread.zoomBy(0.7f);
+ assertNoScaleChange(currScale);
+ }
+
+ public void testScaleChangeCallbackMatchesGetScale() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ assertFalse(mWebViewClient.onScaleChangedCalled());
+
+ setUpPage();
+
+ assertFalse(mWebViewClient.onScaleChangedCalled());
+ assertTrue(mOnUiThread.zoomIn());
+ ScaleChangedState state = mWebViewClient.waitForNextScaleChange();
+ assertEquals(
+ "Expected onScaleChanged arg 2 (new scale) to equal view.getScale()",
+ state.mNewScale, mOnUiThread.getScale());
+ }
+
+ private void assertNoScaleChange(float currScale) {
+ // We sleep to assert to the best of our ability
+ // that a scale change does *not* happen.
+ try {
+ Thread.sleep(500);
+ assertFalse(mWebViewClient.onScaleChangedCalled());
+ assertEquals(currScale, mOnUiThread.getScale());
+ } catch (InterruptedException e) {
+ fail("Interrupted");
+ }
+ }
+
+ private static final class ScaleChangedState {
+ public float mOldScale;
+ public float mNewScale;
+ public boolean mCanZoomIn;
+ public boolean mCanZoomOut;
+
+ ScaleChangedState(WebView view, float oldScale, float newScale) {
+ mOldScale = oldScale;
+ mNewScale = newScale;
+ mCanZoomIn = view.canZoomIn();
+ mCanZoomOut = view.canZoomOut();
+ }
+ }
+
+ private void pollingCheckForCanZoomIn() {
+ new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
+ @Override
+ protected boolean check() {
+ return mOnUiThread.canZoomIn();
+ }
+ }.run();
+ }
+
+ private final class ScaleChangedWebViewClient extends WaitForLoadedClient {
+ private BlockingQueue<ScaleChangedState> mCallQueue;
+
+ public ScaleChangedWebViewClient() {
+ super(mOnUiThread);
+ mCallQueue = new LinkedBlockingQueue<>();
+ }
+
+ @Override
+ public void onScaleChanged(WebView view, float oldScale, float newScale) {
+ super.onScaleChanged(view, oldScale, newScale);
+ mCallQueue.add(new ScaleChangedState(view, oldScale, newScale));
+ }
+
+ public float expectZoomBy(float currentScale, float scaleAmount) {
+ assertTrue(scaleAmount != 1.0f);
+
+ float nextScale = currentScale * scaleAmount;
+ ScaleChangedState state = waitForNextScaleChange();
+ assertEquals(currentScale, state.mOldScale);
+
+ // Check that we zoomed in the expected direction wrt. the current scale.
+ if (scaleAmount > 1.0f) {
+ assertTrue(
+ "Expected new scale > current scale when zooming in",
+ state.mNewScale > currentScale);
+ } else {
+ assertTrue(
+ "Expected new scale < current scale when zooming out",
+ state.mNewScale < currentScale);
+ }
+
+ // If we hit the zoom limit, then the new scale should be between the old scale
+ // and the expected new scale. Otherwise it should equal the expected new scale.
+ if (Math.abs(nextScale - state.mNewScale) > PAGE_SCALE_EPSILON) {
+ if (scaleAmount > 1.0f) {
+ assertFalse(state.mCanZoomIn);
+ assertTrue(
+ "Expected new scale <= requested scale when zooming in past limit",
+ state.mNewScale <= nextScale);
+ } else {
+ assertFalse(state.mCanZoomOut);
+ assertTrue(
+ "Expected new scale >= requested scale when zooming out past limit",
+ state.mNewScale >= nextScale);
+ }
+ }
+
+ return state.mNewScale;
+ }
+
+ public float expectZoomOut(float currentScale) {
+ ScaleChangedState state = waitForNextScaleChange();
+ assertEquals(currentScale, state.mOldScale);
+ assertTrue(state.mNewScale < currentScale);
+ return state.mNewScale;
+ }
+
+ public float expectZoomIn(float currentScale) {
+ ScaleChangedState state = waitForNextScaleChange();
+ assertEquals(currentScale, state.mOldScale);
+ assertTrue(state.mNewScale > currentScale);
+ return state.mNewScale;
+ }
+
+ public ScaleChangedState waitForNextScaleChange() {
+ return WebkitUtils.waitForNextQueueElement(mCallQueue);
+ }
+
+ public boolean onScaleChangedCalled() {
+ return mCallQueue.size() > 0;
+ }
+ }
+}
diff --git a/tests/tests/widget/Android.bp b/tests/tests/widget/Android.bp
new file mode 100644
index 0000000..5887cb8
--- /dev/null
+++ b/tests/tests/widget/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "CtsWidgetTestCases",
+ defaults: ["cts_defaults"],
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ "android-support-test",
+ "mockito-target-minus-junit4",
+ "android-common",
+ "compatibility-device-util",
+ "ctstestrunner",
+ "platform-test-annotations",
+ ],
+
+ libs: ["android.test.runner.stubs"],
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ // TODO: Move away from using hidden platform APIs b/72044662
+ platform_apis: true,
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ "cts_instant",
+ ],
+
+}
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
deleted file mode 100644
index 66473af..0000000
--- a/tests/tests/widget/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
- androidx.annotation_annotation \
- android-support-test \
- mockito-target-minus-junit4 \
- android-common \
- compatibility-device-util \
- ctstestrunner \
- platform-test-annotations
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsWidgetTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index 49b0f64..39ddda0 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -69,6 +69,7 @@
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.EdgeEffect;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
@@ -1127,6 +1128,27 @@
}
}
+ @SmallTest
+ @UiThreadTest
+ @Test
+ public void testEdgeEffectColors() {
+ int defaultColor = new EdgeEffect(mListView.getContext()).getColor();
+ assertEquals(mListView.getTopEdgeEffectColor(), defaultColor);
+ assertEquals(mListView.getBottomEdgeEffectColor(), defaultColor);
+
+ mListView.setEdgeEffectColor(Color.BLUE);
+ assertEquals(mListView.getTopEdgeEffectColor(), Color.BLUE);
+ assertEquals(mListView.getBottomEdgeEffectColor(), Color.BLUE);
+
+ mListView.setTopEdgeEffectColor(Color.RED);
+ assertEquals(mListView.getTopEdgeEffectColor(), Color.RED);
+ assertEquals(mListView.getBottomEdgeEffectColor(), Color.BLUE);
+
+ mListView.setBottomEdgeEffectColor(Color.GREEN);
+ assertEquals(mListView.getTopEdgeEffectColor(), Color.RED);
+ assertEquals(mListView.getBottomEdgeEffectColor(), Color.GREEN);
+ }
+
// Helper method that emulates fast scroll by dragging along the right edge of our ListView.
private void verifyFastScroll() throws Throwable {
setAdapter();
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index f083053..d3c685a 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -72,6 +72,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -901,6 +902,74 @@
() -> mPopupWindow.showAtLocation(anchorView, Gravity.BOTTOM, 0, 0), false);
}
+ @Test
+ public void testEnterExitTransitionAsDropDownWithCustomBounds() throws Throwable {
+ final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+ final Rect epicenter = new Rect(20, 50, 22, 80);
+ verifyTransitionEpicenterChange(
+ () -> mPopupWindow.showAsDropDown(anchorView, 0, 0), epicenter);
+ }
+
+ private void verifyTransitionEpicenterChange(Runnable showRunnable, Rect epicenterBounds)
+ throws Throwable {
+ TransitionListener enterListener = mock(TransitionListener.class);
+ Transition enterTransition = new BaseTransition();
+ enterTransition.addListener(enterListener);
+
+ TransitionListener exitListener = mock(TransitionListener.class);
+ Transition exitTransition = new BaseTransition();
+ exitTransition.addListener(exitListener);
+
+ OnDismissListener dismissListener = mock(OnDismissListener.class);
+
+ mPopupWindow = createPopupWindow(createPopupContent(CONTENT_SIZE_DP, CONTENT_SIZE_DP));
+ mPopupWindow.setEnterTransition(enterTransition);
+ mPopupWindow.setExitTransition(exitTransition);
+ mPopupWindow.setOnDismissListener(dismissListener);
+
+ ArgumentCaptor<Transition> captor = ArgumentCaptor.forClass(Transition.class);
+
+ mActivityRule.runOnUiThread(showRunnable);
+ mInstrumentation.waitForIdleSync();
+
+ verify(enterListener, times(1)).onTransitionStart(captor.capture());
+ final Rect oldEpicenterStart = new Rect(captor.getValue().getEpicenter());
+
+ mActivityRule.runOnUiThread(mPopupWindow::dismiss);
+ mInstrumentation.waitForIdleSync();
+
+ verify(exitListener, times(1)).onTransitionStart(captor.capture());
+ final Rect oldEpicenterExit = new Rect(captor.getValue().getEpicenter());
+
+ mPopupWindow.setEpicenterBounds(epicenterBounds);
+ mActivityRule.runOnUiThread(showRunnable);
+ mInstrumentation.waitForIdleSync();
+
+ verify(enterListener, times(2)).onTransitionStart(captor.capture());
+ final Rect newEpicenterStart = new Rect(captor.getValue().getEpicenter());
+
+ mActivityRule.runOnUiThread(mPopupWindow::dismiss);
+ mInstrumentation.waitForIdleSync();
+
+ verify(exitListener, times(2)).onTransitionStart(captor.capture());
+
+ final Rect newEpicenterExit = new Rect(captor.getValue().getEpicenter());
+
+ verifyEpicenters(oldEpicenterStart, newEpicenterStart, epicenterBounds);
+ verifyEpicenters(oldEpicenterExit, newEpicenterExit, epicenterBounds);
+
+ }
+
+ private void verifyEpicenters(Rect actualOld, Rect actualNew, Rect passed) {
+ Rect oldCopy = new Rect(actualOld);
+ int left = oldCopy.left;
+ int top = oldCopy.top;
+ oldCopy.set(passed);
+ oldCopy.offset(left, top);
+
+ assertEquals(oldCopy, actualNew);
+ }
+
private void verifyEnterExitTransition(Runnable showRunnable, boolean showAgain)
throws Throwable {
TransitionListener enterListener = mock(TransitionListener.class);
@@ -1139,6 +1208,47 @@
}
@Test
+ public void testAccessClippingToScreenEnabled() {
+ mPopupWindow = new PopupWindow(mActivity);
+ assertFalse(mPopupWindow.isClipToScreenEnabled());
+
+ mPopupWindow.setClipToScreenEnabled(true);
+ assertTrue(mPopupWindow.isClipToScreenEnabled());
+ }
+
+ @Test
+ public void testAccessLayoutInScreenEnabled() {
+ mPopupWindow = new PopupWindow(mActivity);
+ assertFalse(mPopupWindow.isLayoutInScreenEnabled());
+
+ mPopupWindow.setLayoutInScreenEnabled(true);
+ assertTrue(mPopupWindow.isLayoutInScreenEnabled());
+ }
+
+ @Test
+ public void testAccessTouchModal() {
+ mPopupWindow = new PopupWindow(mActivity);
+ assertTrue(mPopupWindow.isTouchModal());
+
+ mPopupWindow.setTouchModal(false);
+ assertFalse(mPopupWindow.isTouchModal());
+ }
+
+ @Test
+ public void testAccessEpicenterBounds() {
+ mPopupWindow = new PopupWindow(mActivity);
+ assertNull(mPopupWindow.getEpicenterBounds());
+
+ final Rect epicenter = new Rect(5, 10, 15, 20);
+
+ mPopupWindow.setEpicenterBounds(epicenter);
+ assertEquals(mPopupWindow.getEpicenterBounds(), epicenter);
+
+ mPopupWindow.setEpicenterBounds(null);
+ assertNull(mPopupWindow.getEpicenterBounds());
+ }
+
+ @Test
public void testAccessOutsideTouchable() {
mPopupWindow = new PopupWindow(mActivity);
assertFalse(mPopupWindow.isOutsideTouchable());
diff --git a/tests/tests/wrap/nowrap/Android.mk b/tests/tests/wrap/nowrap/Android.mk
index 8fd1015..094f0f0 100644
--- a/tests/tests/wrap/nowrap/Android.mk
+++ b/tests/tests/wrap/nowrap/Android.mk
@@ -35,4 +35,6 @@
# Jarjar to make WrapTest unique.
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_PACKAGE)
diff --git a/tests/tests/wrap/wrap_debug/Android.mk b/tests/tests/wrap/wrap_debug/Android.mk
index c67e191..71c517b 100644
--- a/tests/tests/wrap/wrap_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug/Android.mk
@@ -42,6 +42,8 @@
# Jarjar to make WrapTest unique.
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
index b768dcf..b2d4ae4 100644
--- a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
@@ -42,6 +42,8 @@
# Jarjar to make WrapTest unique.
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_nodebug/Android.mk b/tests/tests/wrap/wrap_nodebug/Android.mk
index 3317f3c..87dc828 100644
--- a/tests/tests/wrap/wrap_nodebug/Android.mk
+++ b/tests/tests/wrap/wrap_nodebug/Android.mk
@@ -42,6 +42,8 @@
# Jarjar to make WrapTest unique.
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
+
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)