Merge "Fix and clean up JS tests." into sc-dev
diff --git a/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml b/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml
index adae36f..ef39ea0 100644
--- a/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml
+++ b/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml
@@ -57,20 +57,6 @@
android:text="@string/biometric_test_strong_authenticate_strongbox_button"
android:enabled="false"/>
<Button
- android:id="@+id/authenticate_ui_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="@string/biometric_test_strong_authenticate_ui_button"
- android:enabled="false"/>
- <Button
- android:id="@+id/authenticate_negative_button_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="@string/biometric_test_negative_button_button"
- android:enabled="false"/>
- <Button
android:id="@+id/authenticate_cancellation_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml b/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml
index c9ab4b5..f37190d 100644
--- a/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml
+++ b/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml
@@ -43,14 +43,6 @@
android:text="@string/biometric_test_weak_enroll"/>
<Button
- android:id="@+id/biometric_test_weak_authenticate_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="@string/biometric_test_weak_authenticate"
- android:enabled="false"/>
-
- <Button
android:id="@+id/biometric_test_weak_authenticate_time_based_keys_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -94,13 +86,6 @@
android:text="@string/biometric_test_reject_first"
android:enabled="false"/>
<Button
- android:id="@+id/authenticate_negative_button_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="@string/biometric_test_negative_button_button"
- android:enabled="false"/>
- <Button
android:id="@+id/authenticate_cancellation_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0eaaea5..1f210ca 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -254,7 +254,7 @@
<string name="biometric_test_category_weak">3) Weak Biometric Tests</string>
<string name="biometric_test_category_combination">4) setUserAuthParams Tests</string>
- <string name="biometric_test_credential_crypto_label">1c: Credential Crypto</string>
+ <string name="biometric_test_credential_crypto_label">1a: Credential Crypto</string>
<string name="biometric_test_credential_crypto_instructions">This test checks that PIN/Pattern/Password successfully unlocks the relevant KeyStore operations. Please
ensure that you have a PIN/Pattern/Password set up.</string>
<string name="biometric_test_credential_crypto_timed_key_strongbox">Create and unlock timed key (StrongBox)</string>
@@ -276,8 +276,6 @@
<string name="biometric_test_invalid_inputs">Test invalid inputs</string>
<!-- Rejecting does not end the authentication lifecycle -->
<string name="biometric_test_reject_first">Reject, then authenticate</string>
- <!-- Negative button callback is received -->
- <string name="biometric_test_negative_button_button">Test Negative Button</string>
<!-- ERROR_CANCELED is received -->
<string name="biometric_test_cancellation_button">Test CancellationSignal</string>
@@ -293,7 +291,6 @@
<string name="biometric_test_strong_check_and_enroll_button">Start enrollment</string>
<string name="biometric_test_strong_authenticate_no_strongbox_button">Authenticate Crypto (without StrongBox)</string>
<string name="biometric_test_strong_authenticate_strongbox_button">Authenticate Crypto (with StrongBox)</string>
- <string name="biometric_test_strong_authenticate_ui_button">Authenticate Crypto UI</string>
<string name="biometric_test_strong_authenticate_invalidated_button">Authenticate Key Invalidated</string>
<string name="biometric_test_strong_authenticate_invalidated_instruction_title">Instructions</string>
<string name="biometric_test_strong_authenticate_invalidated_instruction_contents">Before starting the next test, please add another enrollment to your strong biometric sensor. If only one enrollment is supported, please remove the current enrollment, then enroll.</string>
@@ -305,7 +302,6 @@
does NOT have ANY biometrics enrolled before starting this test. After passing the first part of the test, it will check various use cases
when authentication is invoked.</string>
<string name="biometric_test_weak_enroll">Start enrollment</string>
- <string name="biometric_test_weak_authenticate">Authenticate</string>
<string name="biometric_test_weak_authenticate_time_based_keys">Authenticate attempt time-based keys</string>
<string name="biometric_test_set_user_authentication_credential_cipher_label">4a: Cipher, Credential</string>
@@ -5347,7 +5343,8 @@
can receive incoming calls after it has been set.
</string>
<string name="dialer_incoming_call_detected">Detected the incoming call. Activity passed.</string>
- <string name="dialer_check_incoming_call_explanation">Call the device.</string>
+ <string name="dialer_check_incoming_call_explanation">Call the device and end the call in the
+ pop up in-call UI.</string>
<string name="dialer_check_incoming_call">Verify Call Received</string>
<!-- Strings for VoicemailSettingsCheck test -->
@@ -5371,6 +5368,7 @@
<string name="dialer_shows_hun_explanation">Call the device.
Check the box if the heads up notification was shown containing the text
\"CTS Incoming Call Notification\", and only one incoming call notification was shown.
+ Also a pop up CtsVerifier in call UI will show.
</string>
<string name="dialer_shows_hun_check_box">HUN shown and meets criteria specified above.</string>
<string name="dialer_incoming_call_hun_teaser">Incoming Call</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java
index 1eba882..461d7cf 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java
@@ -141,52 +141,6 @@
startActivityForResult(enrollIntent, requestCode);
}
- void testBiometricUI(Utils.VerifyRandomContents contents, int allowedAuthenticators) {
- Utils.showInstructionDialog(this,
- R.string.biometric_test_ui_instruction_dialog_title,
- R.string.biometric_test_ui_instruction_dialog_contents,
- R.string.biometric_test_ui_instruction_dialog_continue,
- (dialog, which) -> {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- // Create the BiometricPrompt with the above random numbers
- final BiometricPrompt.Builder builder =
- new BiometricPrompt.Builder(this);
- builder.setAllowedAuthenticators(allowedAuthenticators);
- builder.setTitle("Title: " + contents.mRandomTitle);
- builder.setSubtitle("Subtitle: " + contents.mRandomSubtitle);
- builder.setDescription("Description: " + contents.mRandomDescription);
- builder.setNegativeButton("Negative Button: "
- + contents.mRandomNegativeButtonText, mExecutor,
- (dialog1, which1) -> {
- // Ignore
- });
- final BiometricPrompt prompt = builder.build();
-
- // When authentication succeeds, check that the values entered by the
- // tester match the generated values.
- prompt.authenticate(new CancellationSignal(), mExecutor,
- new BiometricPrompt.AuthenticationCallback() {
- @Override
- public void onAuthenticationSucceeded(
- BiometricPrompt.AuthenticationResult result) {
- final int authenticationType = result.getAuthenticationType();
- if (authenticationType !=
- BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC) {
- showToastAndLog("Unexpected authenticationType: "
- + authenticationType);
- return;
- }
-
- Utils.showUIVerificationDialog(AbstractBaseTest.this,
- R.string.biometric_test_ui_verification_dialog_title,
- R.string.biometric_test_ui_verification_dialog_check,
- contents);
- }
- });
- }
- });
- }
-
/**
* When both credential and biometrics are enrolled, check that the user is able to
* authenticate with biometric.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java
index 04b4add..ff2d114 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java
@@ -69,25 +69,21 @@
private Button mCheckAndEnrollButton;
private Button mAuthenticateWithoutStrongBoxButton;
private Button mAuthenticateWithStrongBoxButton;
- private Button mAuthenticateUIButton;
private Button mAuthenticateCredential1Button; // setDeviceCredentialAllowed(true), biometric
private Button mAuthenticateCredential2Button; // setDeviceCredentialAllowed(true), credential
private Button mAuthenticateCredential3Button; // setAllowedAuthenticators(CREDENTIAL|BIOMETRIC)
private Button mCheckInvalidInputsButton;
private Button mRejectThenAuthenticateButton;
- private Button mNegativeButtonButton;
private Button mCancellationButton;
private Button mKeyInvalidatedButton;
private boolean mAuthenticateWithoutStrongBoxPassed;
private boolean mAuthenticateWithStrongBoxPassed;
- private boolean mAuthenticateUIPassed;
private boolean mAuthenticateCredential1Passed;
private boolean mAuthenticateCredential2Passed;
private boolean mAuthenticateCredential3Passed;
private boolean mCheckInvalidInputsPassed;
private boolean mRejectThenAuthenticatePassed;
- private boolean mNegativeButtonPassed;
private boolean mCancellationButtonPassed;
private boolean mKeyInvalidatedStrongboxPassed;
private boolean mKeyInvalidatedNoStrongboxPassed;
@@ -106,13 +102,11 @@
mCheckAndEnrollButton.setEnabled(false);
mAuthenticateWithoutStrongBoxButton.setEnabled(true);
mAuthenticateWithStrongBoxButton.setEnabled(true);
- mAuthenticateUIButton.setEnabled(true);
mAuthenticateCredential1Button.setEnabled(true);
mAuthenticateCredential2Button.setEnabled(true);
mAuthenticateCredential3Button.setEnabled(true);
mCheckInvalidInputsButton.setEnabled(true);
mRejectThenAuthenticateButton.setEnabled(true);
- mNegativeButtonButton.setEnabled(true);
mCancellationButton.setEnabled(true);
} else {
showToastAndLog("Unexpected result after enrollment: " + biometricStatus);
@@ -129,7 +123,6 @@
mCheckAndEnrollButton = findViewById(R.id.check_and_enroll_button);
mAuthenticateWithoutStrongBoxButton = findViewById(R.id.authenticate_no_strongbox_button);
mAuthenticateWithStrongBoxButton = findViewById(R.id.authenticate_strongbox_button);
- mAuthenticateUIButton = findViewById(R.id.authenticate_ui_button);
mAuthenticateCredential1Button = findViewById(
R.id.authenticate_credential_setDeviceCredentialAllowed_biometric_button);
mAuthenticateCredential2Button = findViewById(
@@ -138,7 +131,6 @@
R.id.authenticate_credential_setAllowedAuthenticators_credential_button);
mCheckInvalidInputsButton = findViewById(R.id.authenticate_invalid_inputs);
mRejectThenAuthenticateButton = findViewById(R.id.authenticate_reject_first);
- mNegativeButtonButton = findViewById(R.id.authenticate_negative_button_button);
mCancellationButton = findViewById(R.id.authenticate_cancellation_button);
mKeyInvalidatedButton = findViewById(R.id.authenticate_key_invalidated_button);
@@ -166,18 +158,6 @@
true /* useStrongBox */);
});
- mAuthenticateUIButton.setOnClickListener((view) -> {
- final Utils.VerifyRandomContents contents = new Utils.VerifyRandomContents(this) {
- @Override
- void onVerificationSucceeded() {
- mAuthenticateUIPassed = true;
- mAuthenticateUIButton.setEnabled(false);
- updatePassButton();
- }
- };
- testBiometricUI(contents, Authenticators.BIOMETRIC_STRONG);
- });
-
mAuthenticateCredential1Button.setOnClickListener((view) -> {
testSetDeviceCredentialAllowed_biometricAuth(() -> {
mAuthenticateCredential1Passed = true;
@@ -218,14 +198,6 @@
});
});
- mNegativeButtonButton.setOnClickListener((view) -> {
- testNegativeButtonCallback(Authenticators.BIOMETRIC_STRONG, () -> {
- mNegativeButtonPassed = true;
- mNegativeButtonButton.setEnabled(false);
- updatePassButton();
- });
- });
-
mCancellationButton.setOnClickListener((view) -> {
testCancellationSignal(Authenticators.BIOMETRIC_STRONG, () -> {
mCancellationButtonPassed = true;
@@ -276,10 +248,10 @@
// completed, let's allow onPause (allow tester to go into settings multiple times if
// needed).
if (mAuthenticateWithoutStrongBoxPassed && mAuthenticateWithStrongBoxPassed
- && mAuthenticateUIPassed && mAuthenticateCredential1Passed
+ && mAuthenticateCredential1Passed
&& mAuthenticateCredential2Passed && mAuthenticateCredential3Passed
&& mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed
- && mNegativeButtonPassed && mCancellationButtonPassed) {
+ && mCancellationButtonPassed) {
return true;
}
@@ -368,10 +340,10 @@
private void updatePassButton() {
if (mAuthenticateWithoutStrongBoxPassed && mAuthenticateWithStrongBoxPassed
- && mAuthenticateUIPassed && mAuthenticateCredential1Passed
+ && mAuthenticateCredential1Passed
&& mAuthenticateCredential2Passed && mAuthenticateCredential3Passed
&& mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed
- && mNegativeButtonPassed && mCancellationButtonPassed) {
+ && mCancellationButtonPassed) {
if (!mKeyInvalidatedStrongboxPassed || !mKeyInvalidatedNoStrongboxPassed) {
mKeyInvalidatedButton.setEnabled(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java
index 6c94ef0..926dab9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java
@@ -23,7 +23,6 @@
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
import android.hardware.biometrics.BiometricPrompt.AuthenticationResult;
-import android.hardware.biometrics.BiometricPrompt.CryptoObject;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.provider.Settings;
@@ -33,8 +32,6 @@
import com.android.cts.verifier.R;
-import javax.crypto.Cipher;
-
/**
* On devices without a weak biometric, ensure that the
* {@link BiometricManager#canAuthenticate(int)} returns
@@ -53,24 +50,20 @@
private static final String TAG = "BiometricWeakTests";
private Button mEnrollButton;
- private Button mAuthenticateButton;
private Button mAuthenticateTimeBasedKeysButton;
private Button mAuthenticateCredential1Button; // setDeviceCredentialAllowed(true), biometric
private Button mAuthenticateCredential2Button; // setDeviceCredentialAllowed(true), credential
private Button mAuthenticateCredential3Button; // setAllowedAuthenticators(CREDENTIAL|BIOMETRIC)
private Button mCheckInvalidInputsButton;
private Button mRejectThenAuthenticateButton;
- private Button mNegativeButtonButton;
private Button mCancellationButton;
- private boolean mAuthenticatePassed;
private boolean mAuthenticateTimeBasedKeysPassed;
private boolean mAuthenticateCredential1Passed;
private boolean mAuthenticateCredential2Passed;
private boolean mAuthenticateCredential3Passed;
private boolean mCheckInvalidInputsPassed;
private boolean mRejectThenAuthenticatePassed;
- private boolean mNegativeButtonPassed;
private boolean mCancellationPassed;
@Override
@@ -86,7 +79,6 @@
getPassButton().setEnabled(false);
mEnrollButton = findViewById(R.id.biometric_test_weak_enroll_button);
- mAuthenticateButton = findViewById(R.id.biometric_test_weak_authenticate_button);
mAuthenticateTimeBasedKeysButton = findViewById(
R.id.biometric_test_weak_authenticate_time_based_keys_button);
mAuthenticateCredential1Button = findViewById(
@@ -97,7 +89,6 @@
R.id.authenticate_credential_setAllowedAuthenticators_credential_button);
mCheckInvalidInputsButton = findViewById(R.id.authenticate_invalid_inputs);
mRejectThenAuthenticateButton = findViewById(R.id.authenticate_reject_first);
- mNegativeButtonButton = findViewById(R.id.authenticate_negative_button_button);
mCancellationButton = findViewById(R.id.authenticate_cancellation_button);
mEnrollButton.setOnClickListener((view) -> {
@@ -105,57 +96,6 @@
new int[]{Authenticators.BIOMETRIC_WEAK, Authenticators.BIOMETRIC_STRONG});
});
- // Note: This button is running multiple sub-tests. This is to prevent misleading results
- // that could be caused by switching biometric sensors between tests.
- // TODO: The test does not allow for onPause to occur. This can be split up now.
- mAuthenticateButton.setOnClickListener((view) -> {
- // Note: Since enrollment request with Authenticators.BIOMETRIC_WEAK requests enrollment
- // for Weak "or stronger", it's possible that the user was asked to enroll a Strong
- // biometric. Thus, generation of keys may or may not pass - both are valid outcomes.
-
- // Check that requesting authentication with WEAK + CryptoObject throws
- // IllegalArgumentException. Note that we're using a CryptoObject without an actual
- // MAC/Signature/Cipher due to the above.
- final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(this);
- builder.setAllowedAuthenticators(Authenticators.BIOMETRIC_WEAK);
- builder.setTitle("This UI should never get shown");
- builder.setNegativeButton("Cancel", mExecutor, (dialog, which) -> {
- // Ignore
- });
- final CryptoObject dummyCrypto = new CryptoObject((Cipher) null);
- final BiometricPrompt prompt = builder.build();
-
- boolean exceptionCaught = false;
- try {
- prompt.authenticate(dummyCrypto, new CancellationSignal(), mExecutor,
- new AuthenticationCallback() {
- // Ignore
- });
- } catch (IllegalArgumentException e) {
- // Expected
- exceptionCaught = true;
- Log.d(TAG, "IllegalArgumentException: " + e);
- }
-
- if (!exceptionCaught) {
- showToastAndLog("Authenticating with BIOMETRIC_WEAK and Crypto is not a valid"
- + " combination");
- return;
- }
-
- // Check that requesting authentication with WEAK works, and that the UI presents the
- // fields set through its public APIs
- final Utils.VerifyRandomContents contents = new Utils.VerifyRandomContents(this) {
- @Override
- void onVerificationSucceeded() {
- mAuthenticatePassed = true;
- mAuthenticateButton.setEnabled(false);
- updatePassButton();
- }
- };
- testBiometricUI(contents, Authenticators.BIOMETRIC_WEAK);
- });
-
// The above test already enforces that authenticate(CryptoObject) throws an exception if
// authentication is attempted with BIOMETRIC_WEAK. The other half of keys (time-based
// keys) do not depend on CryptoObject, and are automatically usable upon completion of
@@ -313,14 +253,6 @@
});
});
- mNegativeButtonButton.setOnClickListener((view) -> {
- testNegativeButtonCallback(Authenticators.BIOMETRIC_WEAK, () -> {
- mNegativeButtonPassed = true;
- mNegativeButtonButton.setEnabled(false);
- updatePassButton();
- });
- });
-
mCancellationButton.setOnClickListener((view) -> {
testCancellationSignal(Authenticators.BIOMETRIC_WEAK, () -> {
mCancellationPassed = true;
@@ -345,11 +277,11 @@
}
private void updatePassButton() {
- if (mAuthenticatePassed && mAuthenticateTimeBasedKeysPassed
+ if (mAuthenticateTimeBasedKeysPassed
&& mAuthenticateCredential1Passed && mAuthenticateCredential2Passed
&& mAuthenticateCredential3Passed && mCheckInvalidInputsPassed
&& mRejectThenAuthenticatePassed
- && mNegativeButtonPassed && mCancellationPassed) {
+ && mCancellationPassed) {
showToastAndLog("All tests passed");
getPassButton().setEnabled(true);
}
@@ -362,14 +294,12 @@
if (biometricStatus == BiometricManager.BIOMETRIC_SUCCESS) {
showToastAndLog("Successfully enrolled, please continue the test");
mEnrollButton.setEnabled(false);
- mAuthenticateButton.setEnabled(true);
mAuthenticateTimeBasedKeysButton.setEnabled(true);
mAuthenticateCredential1Button.setEnabled(true);
mAuthenticateCredential2Button.setEnabled(true);
mAuthenticateCredential3Button.setEnabled(true);
mCheckInvalidInputsButton.setEnabled(true);
mRejectThenAuthenticateButton.setEnabled(true);
- mNegativeButtonButton.setEnabled(true);
mCancellationButton.setEnabled(true);
} else {
showToastAndLog("Unexpected result after enrollment: " + biometricStatus);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
index 6563e7e..7b90221 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
@@ -20,21 +20,14 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
-import android.hardware.biometrics.BiometricManager;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
-import android.text.InputType;
import android.util.Log;
-import android.widget.EditText;
-import android.widget.LinearLayout;
import android.widget.Toast;
-import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
-import java.security.PublicKey;
import java.security.Signature;
-import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
@@ -161,91 +154,6 @@
dialog.show();
}
- static abstract class VerifyRandomContents {
- final Context mContext;
- final String mRandomTitle;
- final String mRandomSubtitle;
- final String mRandomDescription;
- final String mRandomNegativeButtonText;
-
- abstract void onVerificationSucceeded();
-
- VerifyRandomContents(Context context) {
- mContext = context;
-
- final Random random = new Random();
- mRandomTitle = String.valueOf(random.nextInt(10000));
- mRandomSubtitle = String.valueOf(random.nextInt(10000));
- mRandomDescription = String.valueOf(random.nextInt(10000));
- mRandomNegativeButtonText = String.valueOf(random.nextInt(10000));
- }
-
- void verifyContents(String titleEntered, String subtitleEntered, String descriptionEntered,
- String negativeEntered) {
- if (!titleEntered.contentEquals(mRandomTitle)) {
- showToastAndLog(mContext, "Title incorrect, "
- + titleEntered + " " + mRandomTitle);
- } else if (!subtitleEntered.contentEquals(mRandomSubtitle)) {
- showToastAndLog(mContext, "Subtitle incorrect, "
- + subtitleEntered + " " + mRandomSubtitle);
- } else if (!descriptionEntered.contentEquals(mRandomDescription)) {
- showToastAndLog(mContext, "Description incorrect, "
- + descriptionEntered + " " + mRandomDescription);
- } else if (!negativeEntered.contentEquals(mRandomNegativeButtonText)) {
- showToastAndLog(mContext, "Negative text incorrect, "
- + negativeEntered + " " + mRandomNegativeButtonText);
- } else {
- showToastAndLog(mContext, "Contents matched!");
- onVerificationSucceeded();
- }
- }
-
- }
-
- static void showUIVerificationDialog(Context context, int titleRes,
- int positiveButtonRes, VerifyRandomContents contents) {
- LinearLayout layout = new LinearLayout(context);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- final EditText titleBox = new EditText(context);
- titleBox.setHint("Title");
- titleBox.setInputType(InputType.TYPE_CLASS_NUMBER);
- layout.addView(titleBox);
-
- final EditText subtitleBox = new EditText(context);
- subtitleBox.setHint("Subtitle");
- subtitleBox.setInputType(InputType.TYPE_CLASS_NUMBER);
- layout.addView(subtitleBox);
-
- final EditText descriptionBox = new EditText(context);
- descriptionBox.setHint("Description");
- descriptionBox.setInputType(InputType.TYPE_CLASS_NUMBER);
- layout.addView(descriptionBox);
-
- final EditText negativeBox = new EditText(context);
- negativeBox.setHint("Negative Button");
- negativeBox.setInputType(InputType.TYPE_CLASS_NUMBER);
- layout.addView(negativeBox);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(titleRes);
- builder.setPositiveButton(positiveButtonRes, (dialog, which) -> {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- final String titleEntered = titleBox.getText().toString();
- final String subtitleEntered = subtitleBox.getText().toString();
- final String descriptionEntered = descriptionBox.getText().toString();
- final String negativeEntered = negativeBox.getText().toString();
-
- contents.verifyContents(titleEntered, subtitleEntered, descriptionEntered,
- negativeEntered);
- }
- });
-
- AlertDialog dialog = builder.create();
- dialog.setView(layout);
- dialog.show();
- }
-
static boolean deviceConfigContains(Context context, int authenticator) {
final Resources res = context.getResources();
final int resId = res.getIdentifier("config_biometric_sensors", "array", "android");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
index a9fd27a..91ef081 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import android.content.Context;
+import android.content.pm.PackageManager;
/**
* Test suite to join a p2p group.
@@ -62,6 +63,10 @@
sTestSuite = new ArrayList<ReqTestCase>();
sTestSuite.add(new P2pClientPbcTestCase(context));
- sTestSuite.add(new P2pClientPinTestCase(context));
+
+ // Remove pin based client for automotive until b/184183917 is resolved.
+ if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ sTestSuite.add(new P2pClientPinTestCase(context));
+ }
}
}
diff --git a/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java b/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java
new file mode 100644
index 0000000..da4bf93
--- /dev/null
+++ b/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.cts.powerpolicy.PowerPolicyTestAnalyzer;
+import android.car.cts.powerpolicy.PowerPolicyTestResult;
+
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.RunUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class PowerPolicyHostTest extends CarHostJUnit4TestCase {
+ private static final String ANDROID_CLIENT_PKG = "android.car.cts.app";
+ private static final String ANDROID_CLIENT_ACTIVITY = ANDROID_CLIENT_PKG
+ + "/.PowerPolicyTestActivity";
+ private static final String SHELL_CMD_HEADER = "am start -n " + ANDROID_CLIENT_ACTIVITY;
+ private static final String TESTCASE_CMD_HEADER = SHELL_CMD_HEADER
+ + " --es \"powerpolicy\" \"TestCase%d,%s\"";
+ private static final String POWER_POLICY_TEST_RESULT_HEADER = "PowerPolicyTestClientResult";
+
+ private static final int MAX_TEST_CASES = 5;
+ private static final long LAUNCH_BUFFER_TIME_MS = 1_000L;
+
+ private final PowerPolicyTestAnalyzer mTestAnalyzer;
+
+ public PowerPolicyHostTest() {
+ mTestAnalyzer = new PowerPolicyTestAnalyzer(this);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ startAndroidClient();
+ makeSureAndroidClientRunning(ANDROID_CLIENT_PKG);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ killAndroidClient(ANDROID_CLIENT_PKG);
+ }
+
+ @Test
+ public void testDefaultPowerPolicyStateMachine() throws Exception {
+ boolean status = true;
+ // create expected test result
+ PowerPolicyTestResult testResult = startTestCase(1);
+
+ // populate the expected test result here.
+ testResult.addCriteria("dumpstate", "6", null);
+
+ // clear the device to the ON state
+ rebootDevice();
+
+ // execute the test sequence
+ dumpPowerState(testResult.getTestcaseNo());
+
+ // snapshot the test result
+ endTestCase(testResult);
+
+ //TODO (b/183449315): assign the return to the status variable
+ testResult.checkTestStatus();
+
+ assertWithMessage("testDefaultPowerPolicyStateMachine").that(status).isTrue();
+ }
+
+ @Test
+ public void testPowerPolicyChange() throws Exception {
+ boolean status = true;
+ // create expected test result
+ PowerPolicyTestResult testResult = startTestCase(2);
+
+ // populate the expected test result here.
+ testResult.addCriteria("dumpstate", "6", null);
+
+ // execute the test sequence
+ dumpPowerPolicy(testResult.getTestcaseNo());
+
+ // snapshot the test result
+ endTestCase(testResult);
+
+ //TODO (b/183449315): assign the return to the status variable
+ testResult.checkTestStatus();
+
+ assertWithMessage("testPowerPolicyChange").that(status).isTrue();
+ }
+
+ @Test
+ public void testPowerPolicySilentMode() throws Exception {
+ boolean status = true;
+ // create expected test result
+ PowerPolicyTestResult testResult = startTestCase(3);
+
+ // populate the expected test result here.
+ testResult.addCriteria("dumpstate", "2", null);
+
+ // execute the test sequence
+ rebootForcedSilent();
+ dumpPowerState(testResult.getTestcaseNo());
+
+ // snapshot the test result
+ endTestCase(testResult);
+
+ //TODO (b/183449315): assign the return to the status variable
+ testResult.checkTestStatus();
+
+ assertWithMessage("testPowerPolicySilentMode").that(status).isTrue();
+ }
+
+ @Test
+ public void testPowerPolicySuspendToRAM() throws Exception {
+ boolean status = true;
+ // create expected test result
+ PowerPolicyTestResult testResult = startTestCase(4);
+
+ // populate the expected test result here.
+ testResult.addCriteria("dumpstate", "6", null);
+
+ // reboot the device to clear it to ON state
+ rebootDevice();
+
+ // execute the test sequence
+ dumpPowerState(testResult.getTestcaseNo());
+
+ // snapshot the test result
+ endTestCase(testResult);
+
+ //TODO (b/183449315): assign the return to the status variable
+ testResult.checkTestStatus();
+
+ assertWithMessage("testPowerPolicySuspendToRAM").that(status).isTrue();
+ }
+
+ @Test
+ public void testNewPowerPolicy() throws Exception {
+ boolean status = true;
+ // create expected test result
+ PowerPolicyTestResult testResult = startTestCase(5);
+
+ // populate the expected test result here.
+ testResult.addCriteria("dumpstate", "6", null);
+
+ // execute the test sequence
+ // create a fake power policy for now to pass the test
+ definePowerPolicy("123", "0 2 4", "1 3 5");
+ applyPowerPolicy("123");
+ dumpPowerPolicy(testResult.getTestcaseNo());
+
+ // snapshot the test result
+ endTestCase(testResult);
+
+ //TODO (b/183449315): assign the return to the status variable
+ testResult.checkTestStatus();
+
+ assertWithMessage("testNewPowerPolicy").that(status).isTrue();
+ }
+
+ public String fetchActivityDumpsys() throws Exception {
+ return executeCommand("shell dumpsys activity %s | grep %s",
+ ANDROID_CLIENT_ACTIVITY, POWER_POLICY_TEST_RESULT_HEADER);
+ }
+
+ private void startAndroidClient() throws Exception {
+ executeCommand(SHELL_CMD_HEADER);
+ }
+
+ private PowerPolicyTestResult startTestCase(int caseNo)
+ throws Exception {
+ PowerPolicyTestResult testResult;
+
+ if (caseNo < 1 || caseNo > MAX_TEST_CASES) {
+ throw new Exception(String.format("invalid test case number %d", caseNo));
+ }
+
+ testResult = new PowerPolicyTestResult(caseNo, mTestAnalyzer);
+ testResult.takeStartSnapshot();
+ executeCommand(TESTCASE_CMD_HEADER, caseNo, "start");
+ return testResult;
+ }
+
+ private void endTestCase(PowerPolicyTestResult testResult) throws Exception {
+ executeCommand(TESTCASE_CMD_HEADER, testResult.getTestcaseNo(), "end");
+ testResult.takeEndSnapshot();
+ }
+
+ private void rebootDevice() throws Exception {
+ executeCommand("svc power reboot");
+ waitForDeviceAvailable();
+ }
+
+ private void rebootForcedSilent() throws Exception {
+ executeCommand("reboot forcedsilent");
+ waitForDeviceAvailable();
+ }
+
+ private void dumpPowerState(int caseNo) throws Exception {
+ executeCommand(TESTCASE_CMD_HEADER, caseNo, "dumpstate");
+ }
+
+ private void dumpPowerPolicy(int caseNo) throws Exception {
+ executeCommand(TESTCASE_CMD_HEADER, caseNo, "dumppolicy");
+ }
+
+ private void definePowerPolicy(String policyId, String enabledComps,
+ String disabledComps) throws Exception {
+ executeCommand("cmd car_service define-power-policy %s --enable %s --disable %s",
+ policyId, enabledComps, disabledComps);
+ }
+
+ private void applyPowerPolicy(String policyId) throws Exception {
+ executeCommand("cmd car_service apply-power-policy %s", policyId);
+ }
+
+ private void waitForDeviceAvailable() throws Exception {
+ // ITestDevice.waitForDeviceAvailable has default boot timeout
+ // Therefore, trying twice is sufficient
+ try {
+ getDevice().waitForDeviceAvailable();
+ } catch (Exception e) {
+ CLog.w("device is not available, trying one more time");
+ getDevice().waitForDeviceAvailable();
+ }
+ }
+
+ private void killAndroidClient(String clientPkgName) throws Exception {
+ executeCommand("am force-stop %s", clientPkgName);
+ }
+
+ private boolean makeSureAndroidClientRunning(String clientPkgName) {
+ int trialCount = 5;
+ while (trialCount > 0) {
+ RunUtil.getDefault().sleep(LAUNCH_BUFFER_TIME_MS);
+ if (checkAndroidClientRunning(clientPkgName)) {
+ return true;
+ }
+ trialCount--;
+ }
+ return false;
+ }
+
+ private boolean checkAndroidClientRunning(String clientPkgName) {
+ String[] pids = getPidsOfProcess(clientPkgName);
+ return pids.length == 1;
+ }
+
+ private String[] getPidsOfProcess(String... processNames) {
+ String output;
+ String param = String.join(" ", processNames);
+ try {
+ output = executeCommand("pidof %s", param).trim();
+ } catch (Exception e) {
+ CLog.w("Cannot get pids of %s", param);
+ return new String[0];
+ }
+ if (output.isEmpty()) {
+ return new String[0];
+ }
+ String[] tokens = output.split("\\s+");
+ return tokens;
+ }
+}
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestAnalyzer.java b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestAnalyzer.java
new file mode 100644
index 0000000..c304fd1
--- /dev/null
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestAnalyzer.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts.powerpolicy;
+
+import android.car.cts.PowerPolicyHostTest;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
+public final class PowerPolicyTestAnalyzer {
+ private final PowerPolicyHostTest mHostTest;
+
+ public PowerPolicyTestAnalyzer(PowerPolicyHostTest hostTest) {
+ mHostTest = hostTest;
+ }
+
+ /**
+ * Compares results.
+ */
+ public boolean checkIfTestResultMatch(TestResultTable result1, TestResultTable result2) {
+ int size = result1.size();
+ if (size != result2.size()) {
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ if (!result1.get(i).equals(result2.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public TestResultTable snapshotTestResult() throws Exception {
+ TestResultTable snapshot = new TestResultTable();
+ String shellOutput = mHostTest.fetchActivityDumpsys();
+ String[] lines = shellOutput.split("\n");
+ for (String line : lines) {
+ String[] tokens = line.split(",");
+ if (tokens.length != 3 || tokens.length != 4) {
+ CLog.w("Malformatted power policy test result: %s", line);
+ return null;
+ }
+ if (tokens.length == 3) {
+ snapshot.add(tokens[0], tokens[1], tokens[2], null);
+ } else {
+ snapshot.add(tokens[0], tokens[1], tokens[2], tokens[3]);
+ }
+ }
+ return snapshot;
+ }
+
+ /**
+ * Subtract the common front TestResultEntry items.
+ */
+ public TestResultTable getDiff(TestResultTable result1, TestResultTable result2) {
+ TestResultTable diff;
+
+ if (result1 != null && result2 != null) {
+ TestResultTable longResult = result1;
+ TestResultTable shortResult = result2;
+ if (longResult.size() < shortResult.size()) {
+ longResult = result2;
+ shortResult = result1;
+ }
+ int shortSize = shortResult.size();
+ int longSize = longResult.size();
+ int idx = 0;
+ diff = new TestResultTable();
+ for (; idx < shortSize; idx++) {
+ if (!shortResult.get(idx).equals(longResult.get(idx))) {
+ break;
+ }
+ }
+ for (; idx < longSize; idx++) {
+ diff.add(longResult.get(idx));
+ }
+ } else if (result1 == null) {
+ diff = result2;
+ } else {
+ diff = result1;
+ }
+ return diff;
+ }
+
+ public TestResultTable getTailDiff(TestResultTable result1, TestResultTable result2) {
+ TestResultTable diff = null;
+
+ if (result1 != null && result2 != null) {
+ TestResultTable longResult = result1;
+ TestResultTable shortResult = result2;
+ if (longResult.size() < shortResult.size()) {
+ longResult = result2;
+ shortResult = result1;
+ }
+ int shortSize = shortResult.size();
+ int longSize = longResult.size();
+ diff = new TestResultTable();
+ for (int idx = shortSize; idx < longSize; idx++) {
+ diff.add(longResult.get(idx));
+ }
+ } else if (result1 == null) {
+ diff = result2;
+ } else {
+ diff = result1;
+ }
+ return diff;
+ }
+}
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestResult.java b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestResult.java
new file mode 100644
index 0000000..5337288
--- /dev/null
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestResult.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts.powerpolicy;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
+public final class PowerPolicyTestResult {
+ private static final String TESTCASE_NAME_HEADER = "Testcase";
+ private final PowerPolicyTestAnalyzer mTestAnalyzer;
+ private final TestResultTable mExpected = new TestResultTable();
+ private TestResultTable mStartSnapshot;
+ private TestResultTable mEndSnapshot;
+ private int mTestcaseNo;
+ private String mTestcaseName;
+
+ public PowerPolicyTestResult(int caseNo, PowerPolicyTestAnalyzer testAnalyzer) {
+ mTestcaseNo = caseNo;
+ mTestcaseName = TESTCASE_NAME_HEADER + caseNo;
+ mTestAnalyzer = testAnalyzer;
+ }
+
+ public int getTestcaseNo() {
+ return mTestcaseNo;
+ }
+
+ /**
+ * Adds test passing criteria.
+ *
+ * <p> For multiple criteria, the order of adding them into this object matters.
+ */
+ public void addCriteria(String action, String powerState, String data) {
+ mExpected.add(mTestcaseName, action, powerState, data);
+ }
+
+ public void takeStartSnapshot() throws Exception {
+ if (mStartSnapshot != null) {
+ return;
+ }
+ mStartSnapshot = mTestAnalyzer.snapshotTestResult();
+ }
+
+ public void takeEndSnapshot() throws Exception {
+ if (mEndSnapshot != null) {
+ return;
+ }
+ mEndSnapshot = mTestAnalyzer.snapshotTestResult();
+ }
+
+ public boolean checkTestStatus() {
+ TestResultTable testResult = null;
+ if (mStartSnapshot == null || mEndSnapshot == null) {
+ CLog.e("start snapshot or end snapshot is null");
+ return false;
+ }
+
+ testResult = mTestAnalyzer.getTailDiff(mStartSnapshot, mEndSnapshot);
+ if (testResult == null) {
+ CLog.e("empty test result");
+ return false;
+ }
+
+ return mTestAnalyzer.checkIfTestResultMatch(mExpected, testResult);
+ }
+}
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/TestResultTable.java b/hostsidetests/car/src/android/car/cts/powerpolicy/TestResultTable.java
new file mode 100644
index 0000000..e8efef7
--- /dev/null
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/TestResultTable.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts.powerpolicy;
+
+import java.util.ArrayList;
+
+/**
+ * TestResultTable consists of a list of TestResultEntry records
+ *
+ * <p>Each record represents one entry line in the device data file,
+ * {@code /storage/emulated/obb/PowerPolicyData.txt}, which records the power
+ * state and policy behavior.
+ */
+public final class TestResultTable {
+ private final ArrayList<TestResultEntry> mTestResults = new ArrayList<TestResultEntry>();
+
+ public int size() {
+ return mTestResults.size();
+ }
+
+ public TestResultEntry get(int i) throws IndexOutOfBoundsException {
+ return mTestResults.get(i);
+ }
+
+ public void add(TestResultEntry entry) {
+ mTestResults.add(entry);
+ }
+
+ public void add(String testcase, String action, String powerState, String data) {
+ add(new TestResultEntry(testcase, action, powerState, data));
+ }
+
+ static final class TestResultEntry {
+ private final String mTestcase;
+ private final String mAction;
+ private final String mPowerState;
+ private final String mData;
+
+ TestResultEntry(String testcase, String action, String powerState, String data) {
+ mTestcase = testcase;
+ mAction = action;
+ mPowerState = powerState;
+ mData = data;
+ }
+
+ boolean equals(TestResultEntry peerEntry) {
+ if ((mTestcase == null && mTestcase != peerEntry.mTestcase)
+ && (mTestcase != null && !mTestcase.equals(peerEntry.mTestcase))) {
+ return false;
+ }
+ if ((mAction == null && mAction != peerEntry.mAction)
+ && (mAction != null && !mAction.equals(peerEntry.mAction))) {
+ return false;
+ }
+ if ((mPowerState == null && mPowerState != peerEntry.mPowerState)
+ && (mPowerState != null && !mPowerState.equals(peerEntry.mPowerState))) {
+ return false;
+ }
+ if ((mData == null && mData != peerEntry.mData)
+ && (mData != null && !mData.equals(peerEntry.mData))) {
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/hostsidetests/packagemanager/domainverification/device/Android.bp b/hostsidetests/packagemanager/domainverification/device/Android.bp
index 081da66..476264fc 100644
--- a/hostsidetests/packagemanager/domainverification/device/Android.bp
+++ b/hostsidetests/packagemanager/domainverification/device/Android.bp
@@ -19,10 +19,6 @@
android_test {
name: "CtsDomainVerificationDeviceTestCases",
srcs: [ "src/**/*.kt" ],
- test_suites: [
- "cts",
- "device-tests",
- ],
defaults: ["cts_defaults"],
sdk_version: "test_current",
static_libs: [
diff --git a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
index 6f96efd..dd17069 100644
--- a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
+++ b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
@@ -216,6 +216,7 @@
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_COARSE_LOCATION_SOURCE, 109);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_MEDIA, 110);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BLUETOOTH_CONNECT, 111);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_UWB_RANGING, 112);
}
private static boolean sWasVerboseLoggingEnabled;
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index a46269c..d859690 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -16,6 +16,8 @@
package android.theme.cts;
+import android.platform.test.annotations.RequiresDevice;
+
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.device.CollectingOutputReceiver;
@@ -145,6 +147,8 @@
super.tearDown();
}
+ // b/183706483
+ @RequiresDevice
public void testThemes() throws Exception {
if (checkHardwareTypeSkipTest()) {
Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Skipped themes test for watch / TV / automotive");
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index a894032..8bbcf58 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -862,8 +862,15 @@
}
static boolean isWiFiConnected(final ConnectivityManager cm, final WifiManager wm) {
- return wm.isWifiEnabled() && cm.getActiveNetwork() != null
- && cm.getNetworkCapabilities(cm.getActiveNetwork()).hasTransport(TRANSPORT_WIFI);
+ if (!wm.isWifiEnabled()) {
+ return false;
+ }
+ final Network network = cm.getActiveNetwork();
+ if (network == null) {
+ return false;
+ }
+ final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
+ return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
}
/**
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index 307c3ce..dfc94f4 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -33,6 +33,7 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
@@ -243,7 +244,7 @@
mNotification = new Notification.Builder(mContext, "channel_id")
.setSmallIcon(1)
.setContentTitle(CONTENT_TITLE)
- .setColorized(true)
+ .setColorized(true).setColor(Color.WHITE)
.build();
assertTrue(mNotification.extras.getBoolean(Notification.EXTRA_COLORIZED));
diff --git a/tests/camera/src/android/hardware/camera2/cts/FlashlightTest.java b/tests/camera/src/android/hardware/camera2/cts/FlashlightTest.java
index fb1bd6c..9b84387 100644
--- a/tests/camera/src/android/hardware/camera2/cts/FlashlightTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/FlashlightTest.java
@@ -53,7 +53,9 @@
@Override
public void setUp() throws Exception {
- super.setUp();
+ //Use all camera ids for system camera testing since we count the number of callbacks here
+ // and when mAdoptShellPerm == true, all camera ids will get callbacks.
+ super.setUp(/*useAll*/true);
// initialize the list of cameras that have a flash unit so it won't interfere with
// flash tests.
@@ -260,13 +262,14 @@
"opened camera");
}
} catch (CameraAccessException e) {
+ int reason = e.getReason();
if ((hasFlash(id) && id.equals(idToOpen) &&
- e.getReason() == CameraAccessException.CAMERA_IN_USE) ||
+ reason == CameraAccessException.CAMERA_IN_USE) ||
(hasFlash(id) && !id.equals(idToOpen) &&
- e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE)) {
+ reason == CameraAccessException.MAX_CAMERAS_IN_USE)) {
continue;
}
- fail("(" + id + ") not expecting: " + e.getMessage());
+ fail("(" + id + ") not expecting: " + e.getMessage() + "reason " + reason);
} catch (IllegalArgumentException e) {
if (hasFlash(id)) {
fail("not expecting IllegalArgumentException");
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
index eca4b32..6d80169 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
@@ -96,7 +96,16 @@
*/
@Override
public void setUp() throws Exception {
- super.setUp();
+ setUp(false);
+ }
+
+ /**
+ * Set up the camera2 test case required environments, including CameraManager,
+ * HandlerThread, Camera IDs, and CameraStateCallback etc.
+ * @param useAll whether all camera ids are to be used for system camera tests
+ */
+ public void setUp(boolean useAll) throws Exception {
+ super.setUp(useAll);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mHandlerThread = new HandlerThread(TAG);
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/Camera2ParameterizedTestCase.java b/tests/camera/utils/src/android/hardware/camera2/cts/Camera2ParameterizedTestCase.java
index 6d90f2e..dcab9ed 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/Camera2ParameterizedTestCase.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/Camera2ParameterizedTestCase.java
@@ -36,10 +36,21 @@
// (mAdoptShellPerm == true), we have only system camera ids in the array and not normal camera
// ids.
protected String[] mCameraIdsUnderTest;
+ protected boolean mUseAll = false;
@Override
public void setUp() throws Exception {
+ setUp(/*useAll*/false);
+ }
+
+ /**
+ * setUp camera2 related properties for parameterized cts tests
+ *
+ * @param useAll whether all camera ids are to be used for system camera tests
+ */
+ public void setUp(boolean useAll) throws Exception {
super.setUp();
+ mUseAll = useAll;
/**
* Workaround for mockito and JB-MR2 incompatibility
*
@@ -68,6 +79,7 @@
private String[] deriveCameraIdsUnderTest() throws Exception {
String[] idsUnderTest =
+ mAdoptShellPerm && mUseAll ? mCameraManager.getCameraIdListNoLazy() :
CameraTestUtils.getCameraIdListForTesting(mCameraManager, mAdoptShellPerm);
assertNotNull("Camera ids shouldn't be null", idsUnderTest);
if (mOverrideCameraId != null) {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index 06ac5ce..b17ec08 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -19,6 +19,9 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeFalse;
import android.accounts.Account;
import android.accounts.AccountManager;
@@ -59,6 +62,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
+import java.util.concurrent.Callable;
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
@@ -556,6 +560,18 @@
}
}
+
+ @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+ @Test
+ public void getPolicyExemptAppsCanOnlyBeDefinedOnAutomotiveBuilds() throws Exception {
+ assumeFalse("device has " + PackageManager.FEATURE_AUTOMOTIVE,
+ sPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+ assertWithMessage("list of policy-exempt apps")
+ .that(invokeWithShellPermissionIdentity(
+ () -> sDevicePolicyManager.getPolicyExemptApps()))
+ .isEmpty();
+ }
+
FullyManagedDeviceProvisioningParams.Builder
createDefaultManagedDeviceProvisioningParamsBuilder() {
return new FullyManagedDeviceProvisioningParams.Builder(
@@ -660,4 +676,13 @@
.filter(packageName -> !systemApps.contains(packageName))
.collect(Collectors.toSet());
}
+
+ private static <T> T invokeWithShellPermissionIdentity(Callable<T> callable) throws Exception {
+ try {
+ sUiAutomation.adoptShellPermissionIdentity();
+ return callable.call();
+ } finally {
+ sUiAutomation.dropShellPermissionIdentity();
+ }
+ }
}
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
index fb454fc..9e61a2d 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
@@ -30,11 +30,14 @@
import android.hardware.biometrics.SensorProperties;
import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
+import android.support.test.uiautomator.UiObject2;
import com.android.server.biometrics.nano.SensorStateProto;
import org.junit.Test;
+import java.util.Random;
+
/**
* Simple tests.
*/
@@ -159,4 +162,63 @@
any());
}
}
+
+ @Test
+ public void testContentsShownDuringBiometricAuth() throws Exception {
+ for (SensorProperties props : mSensorProperties) {
+ try (BiometricTestSession session =
+ mBiometricManager.createTestSession(props.getSensorId())) {
+ enrollForSensor(session, props.getSensorId());
+
+ final Random random = new Random();
+ final String randomTitle = String.valueOf(random.nextInt(10000));
+ final String randomSubtitle = String.valueOf(random.nextInt(10000));
+ final String randomDescription = String.valueOf(random.nextInt(10000));
+ final String randomNegativeButtonText = String.valueOf(random.nextInt(10000));
+
+ showDefaultBiometricPrompt(session, props.getSensorId(), 0 /* userId */,
+ true /* requireConfirmation */, randomTitle, randomSubtitle,
+ randomDescription, randomNegativeButtonText);
+
+ final UiObject2 actualTitle = findView(TITLE_VIEW);
+ final UiObject2 actualSubtitle = findView(SUBTITLE_VIEW);
+ final UiObject2 actualDescription = findView(DESCRIPTION_VIEW);
+ final UiObject2 actualNegativeButton = findView(BUTTON_ID_NEGATIVE);
+ assertEquals(randomTitle, actualTitle.getText());
+ assertEquals(randomSubtitle, actualSubtitle.getText());
+ assertEquals(randomDescription, actualDescription.getText());
+ assertEquals(randomNegativeButtonText, actualNegativeButton.getText());
+
+ // Finish auth
+ successfullyAuthenticate(session, 0 /* userId */);
+ }
+ }
+ }
+
+ @Test
+ public void testContentsShownDuringCredentialAuth() throws Exception {
+ try (CredentialSession session = new CredentialSession()){
+ session.setCredential();
+
+ final Random random = new Random();
+ final String randomTitle = String.valueOf(random.nextInt(10000));
+ final String randomSubtitle = String.valueOf(random.nextInt(10000));
+ final String randomDescription = String.valueOf(random.nextInt(10000));
+
+ BiometricPrompt.AuthenticationCallback callback =
+ mock(BiometricPrompt.AuthenticationCallback.class);
+ showCredentialOnlyBiometricPromptWithContents(callback, new CancellationSignal(),
+ true /* shouldShow */, randomTitle, randomSubtitle, randomDescription);
+
+ final UiObject2 actualTitle = findView(TITLE_VIEW);
+ final UiObject2 actualSubtitle = findView(SUBTITLE_VIEW);
+ final UiObject2 actualDescription = findView(DESCRIPTION_VIEW);
+ assertEquals(randomTitle, actualTitle.getText());
+ assertEquals(randomSubtitle, actualSubtitle.getText());
+ assertEquals(randomDescription, actualDescription.getText());
+
+ // Finish auth
+ successfullyEnterCredential();
+ }
+ }
}
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
index 0484357..34f51fd 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
@@ -86,6 +86,11 @@
protected static final String BUTTON_ID_CONFIRM = "button_confirm";
protected static final String BUTTON_ID_TRY_AGAIN = "button_try_again";
+ // Biometric text contents
+ protected static final String TITLE_VIEW = "title";
+ protected static final String SUBTITLE_VIEW = "subtitle";
+ protected static final String DESCRIPTION_VIEW = "description";
+
protected static final String VIEW_ID_PASSWORD_FIELD = "lockPassword";
@NonNull protected Instrumentation mInstrumentation;
@@ -207,6 +212,7 @@
// Wait for any animations to complete. Ideally, this should be reflected in
// STATE_SHOWING_DEVICE_CREDENTIAL, but SysUI and BiometricService are different processes
// so we'd need to add some additional plumbing. We can improve this in the future.
+ // TODO(b/152240892)
Thread.sleep(1000);
// Enter credential. AuthSession done, authentication callback received
@@ -248,19 +254,38 @@
@NonNull BiometricPrompt.AuthenticationCallback callback,
@NonNull CancellationSignal cancellationSignal,
boolean shouldShow) throws Exception {
+ showCredentialOnlyBiometricPromptWithContents(callback, cancellationSignal, shouldShow,
+ "Title", "Subtitle", "Description");
+ }
+
+ /**
+ * Shows a BiometricPrompt that specifies {@link Authenticators#DEVICE_CREDENTIAL}
+ * and the specified contents.
+ */
+ protected void showCredentialOnlyBiometricPromptWithContents(
+ @NonNull BiometricPrompt.AuthenticationCallback callback,
+ @NonNull CancellationSignal cancellationSignal, boolean shouldShow,
+ @NonNull String title, @NonNull String subtitle,
+ @NonNull String description) throws Exception {
final Handler handler = new Handler(Looper.getMainLooper());
final Executor executor = handler::post;
final BiometricPrompt prompt = new BiometricPrompt.Builder(mContext)
- .setTitle("Title")
- .setSubtitle("Subtitle")
- .setDescription("Description")
+ .setTitle(title)
+ .setSubtitle(subtitle)
+ .setDescription(description)
.setAllowedAuthenticators(Authenticators.DEVICE_CREDENTIAL)
.setAllowBackgroundAuthentication(true)
.build();
prompt.authenticate(cancellationSignal, executor, callback);
-
mInstrumentation.waitForIdleSync();
+
+ // Wait for any animations to complete. Ideally, this should be reflected in
+ // STATE_SHOWING_DEVICE_CREDENTIAL, but SysUI and BiometricService are different processes
+ // so we'd need to add some additional plumbing. We can improve this in the future.
+ // TODO(b/152240892)
+ Thread.sleep(1000);
+
if (shouldShow) {
waitForState(STATE_SHOWING_DEVICE_CREDENTIAL);
BiometricServiceState state = getCurrentState();
@@ -289,8 +314,14 @@
.build();
prompt.authenticate(cancellationSignal, executor, callback);
-
mInstrumentation.waitForIdleSync();
+
+ // Wait for any animations to complete. Ideally, this should be reflected in
+ // STATE_SHOWING_DEVICE_CREDENTIAL, but SysUI and BiometricService are different processes
+ // so we'd need to add some additional plumbing. We can improve this in the future.
+ // TODO(b/152240892)
+ Thread.sleep(1000);
+
if (shouldShow) {
waitForState(STATE_SHOWING_DEVICE_CREDENTIAL);
BiometricServiceState state = getCurrentState();
@@ -302,18 +333,20 @@
/**
* Shows the default BiometricPrompt (sensors meeting BIOMETRIC_WEAK) with a negative button,
- * and fakes successful authentication via TestApis.
+ * but does not complete authentication. In other words, the dialog will stay on the screen.
*/
- protected void showDefaultBiometricPromptAndAuth(@NonNull BiometricTestSession session,
- int sensorId,
- int userId) throws Exception {
+ protected void showDefaultBiometricPrompt(@NonNull BiometricTestSession session, int sensorId,
+ int userId, boolean requireConfirmation, @NonNull String title,
+ @NonNull String subtitle, @NonNull String description,
+ @NonNull String negativeButtonText) throws Exception {
final Handler handler = new Handler(Looper.getMainLooper());
final Executor executor = handler::post;
final BiometricPrompt prompt = new BiometricPrompt.Builder(mContext)
- .setTitle("Title")
- .setSubtitle("Subtitle")
- .setDescription("Description")
- .setNegativeButton("Negative Button", executor, (dialog, which) -> {
+ .setTitle(title)
+ .setSubtitle(subtitle)
+ .setDescription(description)
+ .setConfirmationRequired(requireConfirmation)
+ .setNegativeButton(negativeButtonText, executor, (dialog, which) -> {
Log.d(TAG, "Negative button pressed");
})
.setAllowBackgroundAuthentication(true)
@@ -334,6 +367,17 @@
});
waitForState(STATE_AUTH_STARTED_UI_SHOWING);
+ }
+
+ /**
+ * Shows the default BiometricPrompt (sensors meeting BIOMETRIC_WEAK) with a negative button,
+ * and fakes successful authentication via TestApis.
+ */
+ protected void showDefaultBiometricPromptAndAuth(@NonNull BiometricTestSession session,
+ int sensorId,
+ int userId) throws Exception {
+ showDefaultBiometricPrompt(session, sensorId, userId, false /* requireConfirmation */,
+ "Title", "Subtitle", "Description", "Negative Button");
successfullyAuthenticate(session, userId);
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index ade0464..e621832 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -577,6 +577,102 @@
runImeVisibilityTestWhenForceStopPackage(true /* instant */);
}
+ @Test
+ public void testRestoreImeVisibility() throws Exception {
+ runRestoreImeVisibility(TestSoftInputMode.UNCHANGED_WITH_BACKWARD_NAV, true);
+ }
+
+ @Test
+ public void testRestoreImeVisibility_noRestoreForAlwaysHidden() throws Exception {
+ runRestoreImeVisibility(TestSoftInputMode.ALWAYS_HIDDEN_WITH_BACKWARD_NAV, false);
+ }
+
+ @Test
+ public void testRestoreImeVisibility_noRestoreForHiddenWithForwardNav() throws Exception {
+ runRestoreImeVisibility(TestSoftInputMode.HIDDEN_WITH_FORWARD_NAV, false);
+ }
+
+ private enum TestSoftInputMode {
+ UNCHANGED_WITH_BACKWARD_NAV,
+ ALWAYS_HIDDEN_WITH_BACKWARD_NAV,
+ HIDDEN_WITH_FORWARD_NAV
+ }
+
+ private void runRestoreImeVisibility(TestSoftInputMode mode, boolean expectImeVisible)
+ throws Exception {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ try (MockImeSession imeSession = MockImeSession.create(
+ instrumentation.getContext(), instrumentation.getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+ final String markerForActivity1 = getTestMarker();
+ final AtomicReference<EditText> editTextRef = new AtomicReference<>();
+ // Launch a test activity with focusing editText to show keyboard
+ TestActivity.startSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ final EditText editText = new EditText(activity);
+ editTextRef.set(editText);
+ editText.setHint("focused editText");
+ editText.setPrivateImeOptions(markerForActivity1);
+ editText.requestFocus();
+ layout.addView(editText);
+ activity.getWindow().getDecorView().getWindowInsetsController().show(ime());
+ if (mode == TestSoftInputMode.ALWAYS_HIDDEN_WITH_BACKWARD_NAV) {
+ activity.getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+ }
+ return layout;
+ });
+
+ expectEvent(stream, editorMatcher("onStartInput", markerForActivity1), TIMEOUT);
+ expectEvent(stream, editorMatcher("onStartInputView", markerForActivity1), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.VISIBLE, TIMEOUT);
+ expectImeVisible(TIMEOUT);
+
+ // Launch another app task activity to hide keyboard
+ TestActivity.startNewTaskSync(activity -> {
+ activity.getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+ return new LinearLayout(activity);
+ });
+ expectEvent(stream, hideSoftInputMatcher(), TIMEOUT);
+ expectEvent(stream, onFinishInputViewMatcher(false), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.GONE, TIMEOUT);
+ expectImeInvisible(TIMEOUT);
+
+ if (mode == TestSoftInputMode.HIDDEN_WITH_FORWARD_NAV) {
+ // Start new TestActivity on the same task with STATE_HIDDEN softInputMode.
+ final String markerForActivity2 = getTestMarker();
+ TestActivity.startSameTaskAndClearTopSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ final EditText editText = new EditText(activity);
+ editText.setHint("focused editText");
+ editText.setPrivateImeOptions(markerForActivity2);
+ editText.requestFocus();
+ layout.addView(editText);
+ activity.getWindow().setSoftInputMode(SOFT_INPUT_STATE_HIDDEN);
+ return layout;
+ });
+ expectEvent(stream, editorMatcher("onStartInput", markerForActivity2), TIMEOUT);
+ } else {
+ // Press back key to back to the first test activity
+ instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ expectEvent(stream, editorMatcher("onStartInput", markerForActivity1), TIMEOUT);
+ }
+
+ // Expect the IME visibility according to expectImeVisible
+ // The expected result could be:
+ // 1) The system can restore the IME visibility to show IME up when navigated back to
+ // the original app task, even the IME is hidden when switching to the next task.
+ // 2) The system won't restore the IME visibility in some softInputMode cases.
+ if (expectImeVisible) {
+ expectImeVisible(TIMEOUT);
+ } else {
+ expectImeInvisible(TIMEOUT);
+ }
+ }
+ }
+
private void runImeVisibilityWhenImeTransitionBetweenActivities(boolean instant)
throws Exception {
try (MockImeSession imeSession = MockImeSession.create(
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
index 75fa553..398e7b6 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
@@ -150,6 +150,20 @@
.getInstrumentation().startActivitySync(intent);
}
+
+ public static TestActivity startSameTaskAndClearTopSync(
+ @NonNull Function<TestActivity, View> activityInitializer) {
+ sInitializer.set(activityInitializer);
+ final Intent intent = new Intent()
+ .setAction(Intent.ACTION_MAIN)
+ .setClass(InstrumentationRegistry.getInstrumentation().getContext(),
+ TestActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return (TestActivity) InstrumentationRegistry
+ .getInstrumentation().startActivitySync(intent);
+ }
+
/**
* Updates {@link WindowManager.LayoutParams#softInputMode}.
*
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index 1826715..a9f5563 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -1561,6 +1561,76 @@
/*unexpectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE);
}
+ @Test
+ public void testGetLastKnownLocationNoteOps() {
+ long timeBeforeLocationAccess = System.currentTimeMillis();
+ mManager.getLastKnownLocation(TEST_PROVIDER);
+ assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
+ /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
+ /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE);
+
+ // Ensure no note ops when provider disabled
+ mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+ timeBeforeLocationAccess = System.currentTimeMillis();
+ mManager.getLastKnownLocation(TEST_PROVIDER);
+ assertNoOpsNotedSinceLastLocationAccess(timeBeforeLocationAccess,
+ AppOpsManager.OPSTR_FINE_LOCATION);
+ }
+
+ @Test
+ public void testGetCurrentLocationNoteOps() throws Exception {
+ long timeBeforeLocationAccess = System.currentTimeMillis();
+ Location loc = createLocation(TEST_PROVIDER, mRandom);
+
+ try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
+ mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
+ Executors.newSingleThreadExecutor(), capture);
+ mManager.setTestProviderLocation(TEST_PROVIDER, loc);
+ assertThat(capture.getLocation(TIMEOUT_MS)).isEqualTo(loc);
+ assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
+ /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
+ /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE);
+ }
+
+ // Ensure no note ops when provider disabled
+ mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+ timeBeforeLocationAccess = System.currentTimeMillis();
+ try (GetCurrentLocationCapture capture2 = new GetCurrentLocationCapture()) {
+ mManager.getCurrentLocation(TEST_PROVIDER, capture2.getCancellationSignal(),
+ Executors.newSingleThreadExecutor(), capture2);
+ mManager.setTestProviderLocation(TEST_PROVIDER, loc);
+ assertNoOpsNotedSinceLastLocationAccess(timeBeforeLocationAccess,
+ AppOpsManager.OPSTR_FINE_LOCATION);
+ }
+ }
+
+ @Test
+ public void testRequestLocationUpdatesNoteOps() throws Exception {
+ long timeBeforeLocationAccess = System.currentTimeMillis();
+ Location loc1 = createLocation(TEST_PROVIDER, mRandom);
+
+ try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
+ mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
+ Executors.newSingleThreadExecutor(), capture);
+
+ mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
+ assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
+ assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
+ /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
+ /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE);
+ }
+
+ // Ensure no note ops when provider disabled
+ mManager.setTestProviderEnabled(TEST_PROVIDER, false);
+ timeBeforeLocationAccess = System.currentTimeMillis();
+ try (LocationListenerCapture capture2 = new LocationListenerCapture(mContext)) {
+ mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
+ Executors.newSingleThreadExecutor(), capture2);
+ assertNoOpsNotedSinceLastLocationAccess(timeBeforeLocationAccess,
+ AppOpsManager.OPSTR_FINE_LOCATION);
+ }
+ }
+
private void accessLocation(String attributionTag) {
Context attributionContext = mContext.createAttributionContext(attributionTag);
attributionContext.getSystemService(LocationManager.class)
@@ -1603,4 +1673,36 @@
automation.dropShellPermissionIdentity();
}
}
+
+ private void assertNoOpsNotedSinceLastLocationAccess(long timeBeforeLocationAccess,
+ @NonNull String unexpectedOp) {
+ final UiAutomation automation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+ automation.adoptShellPermissionIdentity(android.Manifest.permission.GET_APP_OPS_STATS);
+ try {
+ final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+ final List<AppOpsManager.PackageOps> affectedPackageOps = appOpsManager
+ .getPackagesForOps(new String[] {unexpectedOp});
+ final int packageCount = affectedPackageOps.size();
+ for (int i = 0; i < packageCount; i++) {
+ final AppOpsManager.PackageOps packageOps = affectedPackageOps.get(i);
+ if (mContext.getPackageName().equals(packageOps.getPackageName())) {
+ // We are pulling stats only for one app op.
+ final List<AppOpsManager.OpEntry> opEntries = packageOps.getOps();
+ final int opEntryCount = opEntries.size();
+ for (int j = 0; j < opEntryCount; j++) {
+ final AppOpsManager.OpEntry opEntry = opEntries.get(j);
+ if (unexpectedOp.equals(opEntry.getOpStr())
+ && opEntry.getLastAccessTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED) >=
+ timeBeforeLocationAccess) {
+ fail("Unexpected access to " + unexpectedOp);
+ }
+
+ }
+ }
+ }
+ } finally {
+ automation.dropShellPermissionIdentity();
+ }
+ }
}
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
new file mode 100644
index 0000000..22f5c02
--- /dev/null
+++ b/tests/mediapc/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Media Performance Class test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="media" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <!-- target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="host" />
+ <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer -->
+ <!-- target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
+ <option name="push-all" value="true" />
+ <option name="media-folder-name" value="CtsMediaPerformanceeClassTestCases-1.0" />
+ <option name="dynamic-config-module" value="CtsMediaV2TestCases" />
+ </target_preparer -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsMediaPerformanceClassTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.mediapc.cts" />
+ </test>
+</configuration>
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index f7cd97f..8e440b4 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -16,13 +16,12 @@
package android.mediapc.cts;
-import android.os.Build;
import android.content.pm.PackageManager;
-import android.util.Log;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
@@ -33,8 +32,6 @@
* Tests the basic aspects of the media performance class.
*/
public class PerformanceClassTest {
- private static final String TAG = "PerformanceClassTest";
-
private boolean isHandheld() {
// handheld nature is not exposed to package manager, for now
// we check for touchscreen and NOT watch and NOT tv
@@ -48,26 +45,15 @@
@SmallTest
@Test
- public void testMediaPerformanceClass() throws Exception {
- int pc = Build.VERSION.MEDIA_PERFORMANCE_CLASS;
-
- Log.d(TAG, "performance class is " + pc);
-
+ public void testMediaPerformanceClassScope() throws Exception {
// if device is not of a performance class, we are done.
- if (pc == 0) {
- return;
+ Assume.assumeTrue("not a device of a valid media performance class", Utils.isPerfClass());
+
+ if (Utils.isRPerfClass()
+ || Utils.isSPerfClass()) {
+ assertTrue("performance class is only defined for Handheld devices",
+ isHandheld());
}
-
- if (pc == Build.VERSION_CODES.R + 1 /* TODO: make this S */) {
- }
- }
-
- // Tests S specific basic requirements
- private void testS() throws Exception {
- assertTrue("performance class is only defined for Handheld devices",
- isHandheld());
-
- // TODO: add more tests
}
}
diff --git a/tests/mediapc/src/android/mediapc/cts/Utils.java b/tests/mediapc/src/android/mediapc/cts/Utils.java
new file mode 100644
index 0000000..c4038cf
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/Utils.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mediapc.cts;
+
+import android.os.Build;
+import android.util.Log;
+
+/**
+ * Test utilities.
+ */
+/* package private */ class Utils {
+ private static final int sPc = Build.VERSION.MEDIA_PERFORMANCE_CLASS;
+
+ private static final String TAG = "PerformanceClassTestUtils";
+
+ static {
+ Log.d(TAG, "performance class is " + sPc);
+ }
+
+ /**
+ * First defined media performance class.
+ */
+ private static final int FIRST_PERFORMANCE_CLASS = Build.VERSION_CODES.R;
+
+ public static boolean isRPerfClass() {
+ return sPc == Build.VERSION_CODES.R;
+ }
+
+ public static boolean isSPerfClass() {
+ return sPc == Build.VERSION_CODES.R + 1; /* TODO: make this S */
+ }
+
+ /**
+ * Latest defined media performance class.
+ */
+ /* TODO: make this S */
+ private static final int LAST_PERFORMANCE_CLASS = Build.VERSION_CODES.R + 1;
+
+ public static int getPerfClass() {
+ return sPc;
+ }
+
+ public static boolean isPerfClass() {
+ return sPc >= FIRST_PERFORMANCE_CLASS &&
+ sPc <= LAST_PERFORMANCE_CLASS;
+ }
+}
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
index 05ecb78..2fe9c65 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
@@ -884,8 +884,8 @@
private void doTestInstallSysTrace(String testApk) throws Exception {
// Async atrace dump uses less resources but requires periodic pulls.
- // Overall timeout of 30secs in 100ms intervals should be enough.
- final int atraceDumpIterations = 300;
+ // Overall timeout of 10secs in 100ms intervals should be enough.
+ final int atraceDumpIterations = 100;
final int atraceDumpDelayMs = 100;
final String expected = "|page_read:";
diff --git a/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java b/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
index cc44f36..857ced0 100644
--- a/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
@@ -118,6 +118,13 @@
mLockCredential.gotoKeyguard();
mLockCredential.enterAndConfirmLockCredential();
launchHomeActivity();
+ Context appContext = InstrumentationRegistry.getTargetContext();
+ KeyguardManager keyguardManager = (KeyguardManager)appContext.
+ getSystemService(Context.KEYGUARD_SERVICE);
+ for (int i = 0; i < 5 && keyguardManager.isDeviceLocked(); i++) {
+ Log.w(TAG, "Wait for keyguardManager unlock device ...");
+ SystemClock.sleep(1000);
+ }
}
@Override
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
index 07136d6..d8de395 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
@@ -1042,6 +1042,12 @@
}
@Test
+ public void testGettingSystemMediaRouter2WithoutPermissionThrowsSecurityException() {
+ assertThrows(SecurityException.class,
+ () -> MediaRouter2.getInstance(mContext, mContext.getPackageName()));
+ }
+
+ @Test
public void markCallbacksAsTested() {
// Due to CTS coverage tool's bug, it doesn't count the callback methods as tested even if
// we have tests for them. This method just directly calls those methods so that the tool
diff --git a/tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java b/tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java
index 8e09880..8de3f5d 100644
--- a/tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java
+++ b/tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java
@@ -37,6 +37,8 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import android.Manifest;
+import android.app.UiAutomation;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaRoute2Info;
@@ -77,6 +79,8 @@
@NonMediaMainlineTest
public class SystemMediaRouter2Test {
private static final String TAG = "SystemMR2Test";
+
+ UiAutomation mUiAutomation;
Context mContext;
private MediaRouter2 mSystemRouter2ForCts;
private MediaRouter2 mAppRouter2;
@@ -107,6 +111,9 @@
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
+ mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_ROUTING);
+
mExecutor = Executors.newSingleThreadExecutor();
mAudioManager = (AudioManager) mContext.getSystemService(AUDIO_SERVICE);
MediaRouter2TestActivity.startActivity(mContext);
@@ -154,6 +161,8 @@
releaseAllSessions();
// unregister callbacks
clearCallbacks();
+
+ mUiAutomation.dropShellPermissionIdentity();
}
@Test
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 5149577..39d0021 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1954,6 +1954,14 @@
android:label="@string/permlab_bluetooth_connect"
android:protectionLevel="dangerous" />
+ <!-- Required to be able to range to devices using uwb.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.UWB_RANGING"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_uwb_ranging"
+ android:label="@string/permlab_uwb_ranging"
+ android:protectionLevel="dangerous" />
+
<!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
user from using them until they are unsuspended.
@hide
diff --git a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
index 56c0f92..a8530fa 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
+++ b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
@@ -44,6 +44,7 @@
import android.Manifest.permission.RECORD_AUDIO
import android.Manifest.permission.SEND_SMS
import android.Manifest.permission.USE_SIP
+import android.Manifest.permission.UWB_RANGING;
import android.Manifest.permission.WRITE_CALENDAR
import android.Manifest.permission.WRITE_CALL_LOG
import android.Manifest.permission.WRITE_CONTACTS
@@ -149,6 +150,7 @@
// runtime permission
expectedPerms.add(BLUETOOTH_CONNECT)
expectedPerms.add(BLUETOOTH_SCAN)
+ expectedPerms.add(UWB_RANGING)
assertThat(expectedPerms).containsExactlyElementsIn(platformRuntimePerms.map { it.name })
}
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
index a1475ff..49c0354 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
@@ -25,21 +25,14 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.setDefaultLauncher;
import android.app.PendingIntent;
-import android.app.appsearch.AppSearchManager;
-import android.app.appsearch.SearchResult;
-import android.app.appsearch.SearchSpec;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
-import android.content.pm.Signature;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
import com.android.compatibility.common.util.CddTest;
@@ -49,13 +42,6 @@
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
/**
* Tests for {@link ShortcutManager} and {@link ShortcutInfo}.
@@ -1428,62 +1414,6 @@
});
}
- public void testUpdateShortcutVisibility_GrantShortcutAccess() throws Exception {
- final List<byte[]> certs = new ArrayList<>(1);
-
- // retrieve cert from package1
- runWithCallerWithStrictMode(mPackageContext1, () -> {
- try {
- final PackageManager pm = mPackageContext1.getPackageManager();
- final String pkgName = mPackageContext1.getPackageName();
- PackageInfo packageInfo = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
- for (Signature signature : packageInfo.signatures) {
- MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
- certs.add(sha256.digest(signature.toByteArray()));
- }
- } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
- }
- });
-
- // Push shortcuts for package2 and make them visible to package1
- runWithCallerWithStrictMode(mPackageContext2, () -> {
- final ShortcutManager manager = getManager();
- for (byte[] cert : certs) {
- manager.updateShortcutVisibility(mPackageContext1.getPackageName(), cert, true);
- }
- assertTrue(manager.setDynamicShortcuts(list(
- makeShortcut("s1", "1a"),
- makeShortcut("s2", "2a"),
- makeShortcut("s3", "3a"))));
- });
-
- // Verify package1 can see these shortcuts
- final Executor executor = Executors.newSingleThreadExecutor();
- runWithCallerWithStrictMode(mPackageContext1, () -> {
- final AppSearchManager apm = mPackageContext1.getSystemService(
- AppSearchManager.class);
- apm.createGlobalSearchSession(executor, res -> {
- assertTrue(res.getErrorMessage(), res.isSuccess());
- res.getResultValue().search("", new SearchSpec.Builder()
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build()
- ).getNextPage(executor, page -> {
- assertTrue(page.getErrorMessage(), page.isSuccess());
- final List<SearchResult> results = page.getResultValue();
- final Set<String> shortcuts =
- new ArraySet<>(results.size());
- for (SearchResult result : results) {
- shortcuts.add(result.getGenericDocument().getUri());
- }
- final Set<String> expected = new ArraySet<>(3);
- expected.add("s1");
- expected.add("s2");
- expected.add("s3");
- assertEquals("Unexpected results", expected, shortcuts);
- });
- });
- });
- }
-
public void testDisableAndEnableShortcut() {
runWithCallerWithStrictMode(mPackageContext1, () -> {
assertTrue(getManager().setDynamicShortcuts(list(
diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java
index e53694b..a7773b5 100644
--- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java
+++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java
@@ -22,6 +22,7 @@
import static org.junit.Assume.assumeThat;
import android.content.Context;
+import android.telephony.TelephonyManager;
import androidx.test.core.app.ApplicationProvider;
@@ -42,6 +43,13 @@
@Override
protected void before() {
Context context = ApplicationProvider.getApplicationContext();
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+
+ // Skip the test if the device doesn't appear to have any multi-SIM capability. The checks
+ // that follow this one are a bit flaky on devices that have an eSIM but don't support
+ // DSDS or DSDA (e.g. crosshatch and blueline).
+ assumeThat("not enough SIMs",
+ telephonyManager.getSupportedModemCount(), greaterThanOrEqualTo(mMinimumSimCount));
RemovableSims removableSims = new RemovableSims(context);
assumeThat(removableSims.getRemovableSimSlotCount(),
diff --git a/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp b/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
index c5bd894..ca1f7b3 100644
--- a/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
+++ b/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
@@ -38,6 +38,11 @@
namespace {
+static struct {
+ jclass clazz;
+ jmethodID onTransactionComplete;
+} gTransactionCompleteListenerClassInfo;
+
#define NANOS_PER_SECOND 1000000000LL
int64_t systemTime() {
struct timespec time;
@@ -216,6 +221,18 @@
return reinterpret_cast<jlong>(buffer);
}
+void SurfaceTransaction_setBuffer(JNIEnv* /*env*/, jclass, jlong surfaceControl,
+ jlong surfaceTransaction, jlong buffer) {
+ ASurfaceTransaction_setBuffer(reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
+ reinterpret_cast<ASurfaceControl*>(surfaceControl),
+ reinterpret_cast<AHardwareBuffer*>(buffer), -1 /* fence */);
+
+ ASurfaceTransaction_setBufferDataSpace(reinterpret_cast<ASurfaceTransaction*>(
+ surfaceTransaction),
+ reinterpret_cast<ASurfaceControl*>(surfaceControl),
+ ADATASPACE_UNKNOWN);
+}
+
jlong SurfaceTransaction_setQuadrantBuffer(
JNIEnv* /*env*/, jclass, jlong surfaceControl, jlong surfaceTransaction,
jint width, jint height, jint colorTopLeft, jint colorTopRight,
@@ -318,6 +335,39 @@
reinterpret_cast<ASurfaceControl*>(surfaceControl), z);
}
+class CallbackListenerWrapper {
+public:
+ explicit CallbackListenerWrapper(JNIEnv* env, jobject object) {
+ env->GetJavaVM(&mVm);
+ mCallbackListenerObject = env->NewGlobalRef(object);
+ ASSERT(mCallbackListenerObject, "Failed to make global ref");
+ }
+
+ ~CallbackListenerWrapper() { getenv()->DeleteGlobalRef(mCallbackListenerObject); }
+
+ void callback(int64_t latchTime) {
+ JNIEnv* env = getenv();
+ env->CallVoidMethod(mCallbackListenerObject,
+ gTransactionCompleteListenerClassInfo.onTransactionComplete, latchTime);
+ }
+
+ static void transactionCallbackThunk(void* context, ASurfaceTransactionStats* stats) {
+ CallbackListenerWrapper* listener = reinterpret_cast<CallbackListenerWrapper*>(context);
+ listener->callback(ASurfaceTransactionStats_getLatchTime(stats));
+ delete listener;
+ }
+
+private:
+ jobject mCallbackListenerObject;
+ JavaVM* mVm;
+
+ JNIEnv* getenv() {
+ JNIEnv* env;
+ mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+ }
+};
+
static void onComplete(void* context, ASurfaceTransactionStats* stats) {
if (!stats) {
return;
@@ -471,36 +521,69 @@
r, g, b, alpha, ADATASPACE_UNKNOWN);
}
-const std::array<JNINativeMethod, 21> JNI_METHODS = {{
- {"nSurfaceTransaction_create", "()J", (void*)SurfaceTransaction_create},
- {"nSurfaceTransaction_delete", "(J)V", (void*)SurfaceTransaction_delete},
- {"nSurfaceTransaction_apply", "(J)V", (void*)SurfaceTransaction_apply},
- {"nSurfaceControl_createFromWindow", "(Landroid/view/Surface;)J",
- (void*)SurfaceControl_createFromWindow},
- {"nSurfaceControl_create", "(J)J", (void*)SurfaceControl_create},
- {"nSurfaceControl_acquire", "(J)V", (void*)SurfaceControl_acquire},
- {"nSurfaceControl_release", "(J)V", (void*)SurfaceControl_release},
- {"nSurfaceTransaction_setSolidBuffer", "(JJIII)J", (void*)SurfaceTransaction_setSolidBuffer},
- {"nSurfaceTransaction_setQuadrantBuffer", "(JJIIIIII)J",
- (void*)SurfaceTransaction_setQuadrantBuffer},
- {"nSurfaceTransaction_releaseBuffer", "(J)V", (void*)SurfaceTransaction_releaseBuffer},
- {"nSurfaceTransaction_setVisibility", "(JJZ)V", (void*)SurfaceTransaction_setVisibility},
- {"nSurfaceTransaction_setBufferOpaque", "(JJZ)V", (void*)SurfaceTransaction_setBufferOpaque},
- {"nSurfaceTransaction_setGeometry", "(JJIIIIIIIII)V", (void*)SurfaceTransaction_setGeometry},
- {"nSurfaceTransaction_setDamageRegion", "(JJIIII)V", (void*)SurfaceTransaction_setDamageRegion},
- {"nSurfaceTransaction_setZOrder", "(JJI)V", (void*)SurfaceTransaction_setZOrder},
- {"nSurfaceTransaction_setOnComplete", "(J)J", (void*)SurfaceTransaction_setOnComplete},
- {"nSurfaceTransaction_checkOnComplete", "(JJ)V", (void*)SurfaceTransaction_checkOnComplete},
- {"nSurfaceTransaction_setDesiredPresentTime", "(JJ)J",
- (void*)SurfaceTransaction_setDesiredPresentTime},
- {"nSurfaceTransaction_setBufferAlpha", "(JJD)V", (void*)SurfaceTransaction_setBufferAlpha},
- {"nSurfaceTransaction_reparent", "(JJJ)V", (void*)SurfaceTransaction_reparent},
- {"nSurfaceTransaction_setColor", "(JJFFFF)V", (void*)SurfaceTransaction_setColor},
+void SurfaceTransaction_setEnableBackPressure(JNIEnv* /*env*/, jclass, jlong surfaceControl,
+ jlong surfaceTransaction,
+ jboolean enableBackPressure) {
+ ASurfaceTransaction_setEnableBackPressure(reinterpret_cast<ASurfaceTransaction*>(
+ surfaceTransaction),
+ reinterpret_cast<ASurfaceControl*>(surfaceControl),
+ enableBackPressure);
+}
+
+void SurfaceTransaction_setOnCompleteCallback(JNIEnv* env, jclass, jlong surfaceTransaction,
+ jobject callback) {
+ void* context = new CallbackListenerWrapper(env, callback);
+ ASurfaceTransaction_setOnComplete(reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
+ reinterpret_cast<void*>(context),
+ CallbackListenerWrapper::transactionCallbackThunk);
+}
+
+const std::array<JNINativeMethod, 24> JNI_METHODS = {{
+ {"nSurfaceTransaction_create", "()J", (void*)SurfaceTransaction_create},
+ {"nSurfaceTransaction_delete", "(J)V", (void*)SurfaceTransaction_delete},
+ {"nSurfaceTransaction_apply", "(J)V", (void*)SurfaceTransaction_apply},
+ {"nSurfaceControl_createFromWindow", "(Landroid/view/Surface;)J",
+ (void*)SurfaceControl_createFromWindow},
+ {"nSurfaceControl_create", "(J)J", (void*)SurfaceControl_create},
+ {"nSurfaceControl_acquire", "(J)V", (void*)SurfaceControl_acquire},
+ {"nSurfaceControl_release", "(J)V", (void*)SurfaceControl_release},
+ {"nSurfaceTransaction_setSolidBuffer", "(JJIII)J",
+ (void*)SurfaceTransaction_setSolidBuffer},
+ {"nSurfaceTransaction_setBuffer", "(JJJ)V", (void*)SurfaceTransaction_setBuffer},
+ {"nSurfaceTransaction_setQuadrantBuffer", "(JJIIIIII)J",
+ (void*)SurfaceTransaction_setQuadrantBuffer},
+ {"nSurfaceTransaction_releaseBuffer", "(J)V", (void*)SurfaceTransaction_releaseBuffer},
+ {"nSurfaceTransaction_setVisibility", "(JJZ)V", (void*)SurfaceTransaction_setVisibility},
+ {"nSurfaceTransaction_setBufferOpaque", "(JJZ)V",
+ (void*)SurfaceTransaction_setBufferOpaque},
+ {"nSurfaceTransaction_setGeometry", "(JJIIIIIIIII)V",
+ (void*)SurfaceTransaction_setGeometry},
+ {"nSurfaceTransaction_setDamageRegion", "(JJIIII)V",
+ (void*)SurfaceTransaction_setDamageRegion},
+ {"nSurfaceTransaction_setZOrder", "(JJI)V", (void*)SurfaceTransaction_setZOrder},
+ {"nSurfaceTransaction_setOnComplete", "(J)J", (void*)SurfaceTransaction_setOnComplete},
+ {"nSurfaceTransaction_checkOnComplete", "(JJ)V", (void*)SurfaceTransaction_checkOnComplete},
+ {"nSurfaceTransaction_setDesiredPresentTime", "(JJ)J",
+ (void*)SurfaceTransaction_setDesiredPresentTime},
+ {"nSurfaceTransaction_setBufferAlpha", "(JJD)V", (void*)SurfaceTransaction_setBufferAlpha},
+ {"nSurfaceTransaction_reparent", "(JJJ)V", (void*)SurfaceTransaction_reparent},
+ {"nSurfaceTransaction_setColor", "(JJFFFF)V", (void*)SurfaceTransaction_setColor},
+ {"nSurfaceTransaction_setEnableBackPressure", "(JJZ)V",
+ (void*)SurfaceTransaction_setEnableBackPressure},
+ {"nSurfaceTransaction_setOnCompleteCallback",
+ "(JLandroid/view/cts/ASurfaceControlTest$TransactionCompleteListener;)V",
+ (void*)SurfaceTransaction_setOnCompleteCallback},
}};
} // anonymous namespace
jint register_android_view_cts_ASurfaceControlTest(JNIEnv* env) {
+ jclass transactionCompleteListenerClazz =
+ env->FindClass("android/view/cts/ASurfaceControlTest$TransactionCompleteListener");
+ gTransactionCompleteListenerClassInfo.clazz =
+ static_cast<jclass>(env->NewGlobalRef(transactionCompleteListenerClazz));
+ gTransactionCompleteListenerClassInfo.onTransactionComplete =
+ env->GetMethodID(transactionCompleteListenerClazz, "onTransactionComplete", "(J)V");
jclass clazz = env->FindClass("android/view/cts/ASurfaceControlTest");
return env->RegisterNatives(clazz, JNI_METHODS.data(), JNI_METHODS.size());
}
diff --git a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
index 45c049e..0aee479 100644
--- a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
+++ b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
@@ -34,6 +34,7 @@
import android.view.animation.LinearInterpolator;
import android.view.cts.surfacevalidator.AnimationFactory;
import android.view.cts.surfacevalidator.CapturedActivity;
+import android.view.cts.surfacevalidator.MultiFramePixelChecker;
import android.view.cts.surfacevalidator.PixelChecker;
import android.view.cts.surfacevalidator.PixelColor;
import android.view.cts.surfacevalidator.SurfaceControlTestCase;
@@ -51,6 +52,7 @@
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
@LargeTest
@RunWith(AndroidJUnit4.class)
@@ -59,6 +61,27 @@
System.loadLibrary("ctsview_jni");
}
+ public interface TransactionCompleteListener {
+ void onTransactionComplete(long latchTime);
+ }
+
+ private static class SyncTransactionCompleteListener implements TransactionCompleteListener {
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+ @Override
+ public void onTransactionComplete(long latchTime) {
+ mCountDownLatch.countDown();
+ }
+
+ public void waitForTransactionComplete() {
+ try {
+ mCountDownLatch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
private static final String TAG = ASurfaceControlTest.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -80,6 +103,7 @@
public void setup() {
mActivity = mActivityRule.getActivity();
mActivity.setLogicalDisplaySize(getLogicalDisplaySize());
+ mActivity.setMinimumCaptureDurationMs(1000);
}
/**
@@ -99,6 +123,51 @@
private abstract class BasicSurfaceHolderCallback implements SurfaceHolder.Callback {
private Set<Long> mSurfaceControls = new HashSet<Long>();
private Set<Long> mBuffers = new HashSet<Long>();
+ private Set<BufferCycler> mBufferCyclers = new HashSet<>();
+
+ // Helper class to submit buffers as fast as possible. The thread submits a buffer,
+ // waits for the transaction complete callback, and then submits the next buffer.
+ class BufferCycler extends Thread {
+ private long mSurfaceControl;
+ private long[] mBuffers;
+ private volatile boolean mStop = false;
+ private int mFrameNumber = 0;
+
+ BufferCycler(long surfaceControl, long[] buffers) {
+ mSurfaceControl = surfaceControl;
+ mBuffers = buffers;
+ }
+
+ private long getNextBuffer() {
+ return mBuffers[mFrameNumber++ % mBuffers.length];
+ }
+
+ @Override
+ public void run() {
+ while (!mStop) {
+ SyncTransactionCompleteListener listener =
+ new SyncTransactionCompleteListener();
+ // Send all buffers in batches so we can stuff the SurfaceFlinger transaction
+ // queue.
+ for (int i = 0; i < mBuffers.length; i++) {
+ long surfaceTransaction = createSurfaceTransaction();
+ setBuffer(mSurfaceControl, surfaceTransaction, getNextBuffer());
+ if (i == 0) {
+ setOnCompleteCallback(surfaceTransaction, listener);
+ }
+ applyAndDeleteSurfaceTransaction(surfaceTransaction);
+ }
+
+ // Wait for one of transactions to be applied before sending more transactions.
+ listener.waitForTransactionComplete();
+ }
+ }
+
+ void end() {
+ mStop = true;
+ }
+ }
+
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
@@ -109,6 +178,13 @@
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
+ for (BufferCycler cycler: mBufferCyclers) {
+ cycler.end();
+ try {
+ cycler.join();
+ } catch (InterruptedException e) {
+ }
+ }
for (Long surfaceControl : mSurfaceControls) {
reparent(surfaceControl, 0);
nSurfaceControl_release(surfaceControl);
@@ -156,18 +232,24 @@
return childSurfaceControl;
}
- public void setSolidBuffer(
+ public long setSolidBuffer(
long surfaceControl, long surfaceTransaction, int width, int height, int color) {
long buffer = nSurfaceTransaction_setSolidBuffer(
surfaceControl, surfaceTransaction, width, height, color);
assertTrue("failed to set buffer", buffer != 0);
mBuffers.add(buffer);
+ return buffer;
}
- public void setSolidBuffer(long surfaceControl, int width, int height, int color) {
+ public long setSolidBuffer(long surfaceControl, int width, int height, int color) {
long surfaceTransaction = createSurfaceTransaction();
- setSolidBuffer(surfaceControl, surfaceTransaction, width, height, color);
+ long buffer = setSolidBuffer(surfaceControl, surfaceTransaction, width, height, color);
applyAndDeleteSurfaceTransaction(surfaceTransaction);
+ return buffer;
+ }
+
+ public void setBuffer(long surfaceControl, long surfaceTransaction, long buffer) {
+ nSurfaceTransaction_setBuffer(surfaceControl, surfaceTransaction, buffer);
}
public void setQuadrantBuffer(long surfaceControl, long surfaceTransaction, int width,
@@ -278,6 +360,25 @@
setColor(surfaceControl, surfaceTransaction, red, green, blue, alpha);
applyAndDeleteSurfaceTransaction(surfaceTransaction);
}
+
+ public void setEnableBackPressure(long surfaceControl, boolean enableBackPressure) {
+ long surfaceTransaction = createSurfaceTransaction();
+ nSurfaceTransaction_setEnableBackPressure(surfaceControl, surfaceTransaction,
+ enableBackPressure);
+ applyAndDeleteSurfaceTransaction(surfaceTransaction);
+ }
+
+ public void setOnCompleteCallback(long surfaceTransaction,
+ TransactionCompleteListener listener) {
+ nSurfaceTransaction_setOnCompleteCallback(surfaceTransaction, listener);
+ }
+
+ public void addBufferCycler(long surfaceControl, long[] buffers) {
+ BufferCycler cycler = new BufferCycler(surfaceControl, buffers);
+ cycler.start();
+ mBufferCyclers.add(cycler);
+ }
+
}
///////////////////////////////////////////////////////////////////////////
@@ -307,7 +408,8 @@
mActivity.verifyTest(new SurfaceControlTestCase(callback, sTranslateAnimationFactory,
pixelChecker,
DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT,
- DEFAULT_BUFFER_WIDTH, DEFAULT_BUFFER_HEIGHT),
+ DEFAULT_BUFFER_WIDTH, DEFAULT_BUFFER_HEIGHT,
+ false /* checkSurfaceViewBoundsOnly */),
mName);
}
@@ -1572,6 +1674,77 @@
});
}
+ @Test
+ public void testSurfaceTransaction_setEnableBackPressure() throws Throwable {
+ int[] colors = new int[] {PixelColor.RED, PixelColor.GREEN, PixelColor.BLUE};
+ BasicSurfaceHolderCallback callback = new BasicSurfaceHolderCallback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ long surfaceControl = createFromWindow(holder.getSurface());
+ setEnableBackPressure(surfaceControl, true);
+ long[] buffers = new long[6];
+ for (int i = 0; i < buffers.length; i++) {
+ buffers[i] = setSolidBuffer(surfaceControl, DEFAULT_LAYOUT_WIDTH,
+ DEFAULT_LAYOUT_HEIGHT, colors[i % colors.length]);
+ }
+ addBufferCycler(surfaceControl, buffers);
+ }
+ };
+
+ MultiFramePixelChecker pixelChecker = new MultiFramePixelChecker(colors) {
+ @Override
+ public boolean checkPixels(int pixelCount, int width, int height) {
+ return pixelCount > 9000 && pixelCount < 11000;
+ }
+ };
+
+ mActivity.verifyTest(new SurfaceControlTestCase(callback, null /* animation factory */,
+ pixelChecker,
+ DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT,
+ DEFAULT_BUFFER_WIDTH, DEFAULT_BUFFER_HEIGHT,
+ true /* checkSurfaceViewBoundsOnly */),
+ mName);
+ }
+
+ @Test
+ public void testSurfaceTransaction_defaultBackPressureDisabled() throws Throwable {
+ int[] colors = new int[] {PixelColor.RED, PixelColor.GREEN, PixelColor.BLUE};
+ BasicSurfaceHolderCallback callback = new BasicSurfaceHolderCallback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ long surfaceControl = createFromWindow(holder.getSurface());
+ // back pressure is disabled by default
+ long[] buffers = new long[6];
+ for (int i = 0; i < buffers.length; i++) {
+ buffers[i] = setSolidBuffer(surfaceControl, DEFAULT_LAYOUT_WIDTH,
+ DEFAULT_LAYOUT_HEIGHT, colors[i % colors.length]);
+ }
+ addBufferCycler(surfaceControl, buffers);
+ }
+ };
+
+ MultiFramePixelChecker pixelChecker = new MultiFramePixelChecker(colors) {
+ @Override
+ public boolean checkPixels(int pixelCount, int width, int height) {
+ return pixelCount > 9000 && pixelCount < 11000;
+ }
+ };
+
+ CapturedActivity.TestResult result = mActivity.runTest(new SurfaceControlTestCase(callback,
+ null /* animation factory */,
+ pixelChecker,
+ DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT,
+ DEFAULT_BUFFER_WIDTH, DEFAULT_BUFFER_HEIGHT,
+ true /* checkSurfaceViewBoundsOnly */));
+
+ assertTrue(result.passFrames > 0);
+
+ // With back pressure disabled, the default config, we expect at least one or more frames to
+ // fail since we expect at least one buffer to be dropped.
+ assertTrue(result.failFrames > 0);
+
+ }
+
///////////////////////////////////////////////////////////////////////////
// Native function prototypes
///////////////////////////////////////////////////////////////////////////
@@ -1585,6 +1758,8 @@
private static native void nSurfaceControl_release(long surfaceControl);
private static native long nSurfaceTransaction_setSolidBuffer(
long surfaceControl, long surfaceTransaction, int width, int height, int color);
+ private static native void nSurfaceTransaction_setBuffer(long surfaceControl,
+ long surfaceTransaction, long buffer);
private static native long nSurfaceTransaction_setQuadrantBuffer(long surfaceControl,
long surfaceTransaction, int width, int height, int colorTopLeft, int colorTopRight,
int colorBottomRight, int colorBottomLeft);
@@ -1617,4 +1792,8 @@
long newParentSurfaceControl, long surfaceTransaction);
private static native void nSurfaceTransaction_setColor(long surfaceControl,
long surfaceTransaction, float r, float g, float b, float alpha);
+ private static native void nSurfaceTransaction_setEnableBackPressure(long surfaceControl,
+ long surfaceTransaction, boolean enableBackPressure);
+ private static native void nSurfaceTransaction_setOnCompleteCallback(long surfaceTransaction,
+ TransactionCompleteListener listener);
}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 8ca8b4c..0362b1a 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -99,6 +99,7 @@
private CountDownLatch mCountDownLatch;
private boolean mProjectionServiceBound = false;
private Point mLogicalDisplaySize = new Point();
+ private long mMinimumCaptureDurationMs = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -203,6 +204,10 @@
return mOnEmbedded ? 100000 : 50000;
}
+ public void setMinimumCaptureDurationMs(long durationMs) {
+ mMinimumCaptureDurationMs = durationMs;
+ }
+
public TestResult runTest(ISurfaceValidatorTestCase animationTestCase) throws Throwable {
TestResult testResult = new TestResult();
if (mOnWatch) {
@@ -220,7 +225,7 @@
final long timeOutMs = mOnEmbedded ? 125000 : 62500;
final long captureDuration = animationTestCase.hasAnimation() ?
- getCaptureDurationMs() : 0;
+ getCaptureDurationMs() : mMinimumCaptureDurationMs;
final long endCaptureDelayMs = START_CAPTURE_DELAY_MS + captureDuration;
final long endDelayMs = endCaptureDelayMs + 1000;
@@ -261,12 +266,8 @@
final Display defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
final int rotation = defaultDisplay.getRotation();
- View testAreaView = findViewById(android.R.id.content);
- Rect boundsToCheck = new Rect(0, 0, testAreaView.getWidth(), testAreaView.getHeight());
- int[] topLeft = new int[2];
- testAreaView.getLocationOnScreen(topLeft);
- boundsToCheck.offset(topLeft[0], topLeft[1]);
-
+ Rect boundsToCheck =
+ animationTestCase.getBoundsToCheck(findViewById(android.R.id.content));
if (boundsToCheck.width() < 90 || boundsToCheck.height() < 90) {
fail("capture bounds too small to be a fullscreen activity: " + boundsToCheck);
}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ISurfaceValidatorTestCase.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ISurfaceValidatorTestCase.java
index 037472b..0de06d2 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ISurfaceValidatorTestCase.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ISurfaceValidatorTestCase.java
@@ -16,6 +16,7 @@
package android.view.cts.surfacevalidator;
import android.content.Context;
+import android.graphics.Rect;
import android.widget.FrameLayout;
public interface ISurfaceValidatorTestCase {
@@ -28,4 +29,12 @@
default boolean hasAnimation() {
return true;
}
+
+ default Rect getBoundsToCheck(FrameLayout parent) {
+ Rect boundsToCheck = new Rect(0, 0, parent.getWidth(), parent.getHeight());
+ int[] topLeft = new int[2];
+ parent.getLocationOnScreen(topLeft);
+ boundsToCheck.offset(topLeft[0], topLeft[1]);
+ return boundsToCheck;
+ }
}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/MultiFramePixelChecker.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/MultiFramePixelChecker.java
new file mode 100644
index 0000000..9ddb116
--- /dev/null
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/MultiFramePixelChecker.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.surfacevalidator;
+
+import android.graphics.Rect;
+import android.media.Image;
+import android.util.Log;
+
+public abstract class MultiFramePixelChecker extends PixelChecker {
+ private static final int PIXEL_STRIDE = 4;
+ private static final String TAG = "PixelChecker";
+
+ private int mMatchingPixelCount = 0;
+ private final PixelColor[] mPixelColors;
+ private int mStartingColorIndex = 0;
+ private boolean mStartingColorFound = false;
+
+ public MultiFramePixelChecker(int[] colors) {
+ mPixelColors = new PixelColor[colors.length];
+ for (int i = 0; i < colors.length; i++) {
+ mPixelColors[i] = new PixelColor(colors[i]);
+ }
+ }
+
+ private PixelColor getColor(long frameNumber) {
+ return mPixelColors[(int) ((frameNumber + mStartingColorIndex) % mPixelColors.length)];
+ }
+
+ private boolean findStartingColor(Image.Plane plane, Rect boundsToCheck) {
+ for (mStartingColorIndex = 0; mStartingColorIndex < mPixelColors.length;
+ mStartingColorIndex++) {
+ int numMatchingPixels = getNumMatchingPixels(mPixelColors[mStartingColorIndex], plane,
+ boundsToCheck);
+ if (checkPixels(numMatchingPixels, 0 , 0)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean validatePlane(Image.Plane plane, long frameNumber, Rect boundsToCheck, int width,
+ int height) {
+ if (!mStartingColorFound) {
+ mStartingColorFound = findStartingColor(plane, boundsToCheck);
+ if (mStartingColorFound) {
+ Log.d(TAG, "Starting color found in frame " + frameNumber);
+ } else {
+ Log.d(TAG, "Starting color not found in frame " + frameNumber);
+ return false;
+ }
+ }
+
+ mMatchingPixelCount = getNumMatchingPixels(getColor(frameNumber), plane, boundsToCheck);
+ return checkPixels(mMatchingPixelCount, width, height);
+ }
+}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelChecker.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelChecker.java
index 821352c..7e1c601 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelChecker.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelChecker.java
@@ -22,7 +22,7 @@
import java.nio.ByteBuffer;
public abstract class PixelChecker {
- private int mBlackishPixelCount = 0;
+ private int mMatchingPixelCount = 0;
private PixelColor mPixelColor;
private static final int PIXEL_STRIDE = 4;
@@ -35,27 +35,10 @@
mPixelColor = new PixelColor(color);
}
- PixelColor getColor() {
- return mPixelColor;
- }
-
- public boolean validatePlane(Image.Plane plane, Rect boundsToCheck, int width, int height) {
- int rowStride = plane.getRowStride();
+ int getNumMatchingPixels(PixelColor expectedColor, Image.Plane plane, Rect boundsToCheck) {
+ int numMatchingPixels = 0;
ByteBuffer buffer = plane.getBuffer();
-
- Trace.beginSection("compare and sum");
-
- final short maxAlpha = getColor().mMaxAlpha;
- final short minAlpha = getColor().mMinAlpha;
- final short maxRed = getColor().mMaxRed;
- final short minRed = getColor().mMinRed;
- final short maxGreen = getColor().mMaxGreen;
- final short minGreen = getColor().mMinGreen;
- final short maxBlue = getColor().mMaxBlue;
- final short minBlue = getColor().mMinBlue;
-
- mBlackishPixelCount = 0;
-
+ int rowStride = plane.getRowStride();
final int bytesWidth = boundsToCheck.width() * PIXEL_STRIDE;
byte[] scanline = new byte[bytesWidth];
for (int row = boundsToCheck.top; row < boundsToCheck.bottom; row++) {
@@ -63,30 +46,42 @@
buffer.get(scanline, 0, scanline.length);
for (int i = 0; i < bytesWidth; i += PIXEL_STRIDE) {
// Format is RGBA_8888 not ARGB_8888
- final int red = scanline[i + 0] & 0xFF;
- final int green = scanline[i + 1] & 0xFF;
- final int blue = scanline[i + 2] & 0xFF;
- final int alpha = scanline[i + 3] & 0xFF;
-
- if (alpha <= maxAlpha
- && alpha >= minAlpha
- && red <= maxRed
- && red >= minRed
- && green <= maxGreen
- && green >= minGreen
- && blue <= maxBlue
- && blue >= minBlue) {
- mBlackishPixelCount++;
+ if (matchesColor(expectedColor, scanline, i)) {
+ numMatchingPixels++;
}
}
}
+ return numMatchingPixels;
+ }
+
+ boolean matchesColor(PixelColor expectedColor, byte[] scanline, int offset) {
+ final int red = scanline[offset + 0] & 0xFF;
+ final int green = scanline[offset + 1] & 0xFF;
+ final int blue = scanline[offset + 2] & 0xFF;
+ final int alpha = scanline[offset + 3] & 0xFF;
+
+ return alpha <= expectedColor.mMaxAlpha
+ && alpha >= expectedColor.mMinAlpha
+ && red <= expectedColor.mMaxRed
+ && red >= expectedColor.mMinRed
+ && green <= expectedColor.mMaxGreen
+ && green >= expectedColor.mMinGreen
+ && blue <= expectedColor.mMaxBlue
+ && blue >= expectedColor.mMinBlue;
+ }
+
+
+ public boolean validatePlane(Image.Plane plane, long frameNumber,
+ Rect boundsToCheck, int width, int height) {
+ Trace.beginSection("compare and sum");
+ mMatchingPixelCount = getNumMatchingPixels(mPixelColor, plane, boundsToCheck);
Trace.endSection();
- return checkPixels(mBlackishPixelCount, width, height);
+ return checkPixels(mMatchingPixelCount, width, height);
}
public String getLastError() {
- return "pixel count = " + mBlackishPixelCount + ")";
+ return "pixel count = " + mMatchingPixelCount + ")";
}
public abstract boolean checkPixels(int matchingPixelCount, int width, int height);
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/RectChecker.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/RectChecker.java
index c97fc0c..e4fd696 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/RectChecker.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/RectChecker.java
@@ -48,7 +48,7 @@
this(new Target(r, p));
}
- public boolean validatePlane(Image.Plane plane, Rect boundsToCheck,
+ public boolean validatePlane(Image.Plane plane, long framenumber, Rect boundsToCheck,
int width, int height) {
for (Target t : mTargets) {
if (validatePlaneForTarget(t, plane, boundsToCheck, width, height) == false) {
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfaceControlTestCase.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfaceControlTestCase.java
index 08d67be..069b42c 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfaceControlTestCase.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfaceControlTestCase.java
@@ -17,6 +17,7 @@
import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.Rect;
import android.view.Gravity;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
@@ -29,7 +30,8 @@
private final FrameLayout.LayoutParams mLayoutParams;
private final AnimationFactory mAnimationFactory;
private final PixelChecker mPixelChecker;
-
+ private final boolean mCheckSurfaceViewBoundsOnly;
+ protected View mSurfaceView;
private final int mBufferWidth;
private final int mBufferHeight;
@@ -59,7 +61,8 @@
public SurfaceControlTestCase(SurfaceHolder.Callback callback,
AnimationFactory animationFactory, PixelChecker pixelChecker,
- int layoutWidth, int layoutHeight, int bufferWidth, int bufferHeight) {
+ int layoutWidth, int layoutHeight, int bufferWidth, int bufferHeight,
+ boolean checkSurfaceViewBoundsOnly) {
mViewFactory = new SurfaceViewFactory(callback);
mLayoutParams =
new FrameLayout.LayoutParams(layoutWidth, layoutHeight, Gravity.LEFT | Gravity.TOP);
@@ -67,13 +70,15 @@
mPixelChecker = pixelChecker;
mBufferWidth = bufferWidth;
mBufferHeight = bufferHeight;
+ mCheckSurfaceViewBoundsOnly = checkSurfaceViewBoundsOnly;
}
public SurfaceControlTestCase(ParentSurfaceConsumer psc,
AnimationFactory animationFactory, PixelChecker pixelChecker,
int layoutWidth, int layoutHeight, int bufferWidth, int bufferHeight) {
this(new ParentSurfaceHolder(psc), animationFactory, pixelChecker,
- layoutWidth, layoutHeight, bufferWidth, bufferHeight);
+ layoutWidth, layoutHeight, bufferWidth, bufferHeight,
+ false /* checkSurfaceViewBoundsOnly*/);
}
public PixelChecker getChecker() {
@@ -86,6 +91,7 @@
ParentSurfaceHolder psh = (ParentSurfaceHolder) mViewFactory.mCallback;
psh.mSurfaceView = (SurfaceView) view;
}
+ mSurfaceView = view;
mParent = parent;
mParent.addView(view, mLayoutParams);
@@ -108,6 +114,16 @@
return mAnimationFactory != null;
}
+ @Override
+ public Rect getBoundsToCheck(FrameLayout parent) {
+ View boundsView = mCheckSurfaceViewBoundsOnly ? mSurfaceView : parent;
+ Rect boundsToCheck = new Rect(0, 0, boundsView.getWidth(), boundsView.getHeight());
+ int[] topLeft = new int[2];
+ boundsView.getLocationOnScreen(topLeft);
+ boundsToCheck.offset(topLeft[0], topLeft[1]);
+ return boundsToCheck;
+ }
+
private class SurfaceViewFactory implements ViewFactory {
private SurfaceHolder.Callback mCallback;
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator2.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator2.java
index 6152dfb..8ecdbd0 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator2.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator2.java
@@ -49,6 +49,7 @@
private int mResultSuccessFrames;
private int mResultFailureFrames;
private SparseArray<Bitmap> mFirstFailures = new SparseArray<>(MAX_CAPTURED_FAILURES);
+ private long mFrameNumber = 0;
private ImageReader.OnImageAvailableListener mOnImageAvailable =
new ImageReader.OnImageAvailableListener() {
@@ -65,7 +66,8 @@
}
Trace.endSection();
- boolean success = mPixelChecker.validatePlane(plane, mBoundsToCheck, mWidth, mHeight);
+ boolean success = mPixelChecker.validatePlane(plane, mFrameNumber++, mBoundsToCheck,
+ mWidth, mHeight);
synchronized (mResultLock) {
mResultLock.notifyAll();
diff --git a/tests/uwb/AndroidManifest.xml b/tests/uwb/AndroidManifest.xml
index adecade..bc75901 100644
--- a/tests/uwb/AndroidManifest.xml
+++ b/tests/uwb/AndroidManifest.xml
@@ -24,5 +24,8 @@
android:label="CTS tests for android.uwb"
android:targetPackage="android.uwb.cts" >
</instrumentation>
+
+ <uses-permission android:name="android.permission.UWB_RANGING"/>
+ <uses-permission android:name="android.permission.UWB_PRIVILEGED"/>
</manifest>