diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-06 20:22:22 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-06 20:22:22 +0000 |
commit | 099c7fa419d07f4fd9de018506716b2366626c5e (patch) | |
tree | 3a0234150436e4998ab38eeff520722f03a9d4ad | |
parent | 8ceadae6f186298b922d1b1fc989c34bdc39bc64 (diff) | |
parent | 97bd3fdea42e0b6fab817b63e67099ee5ff04dbe (diff) | |
download | cts-android14-mainline-networking-release.tar.gz |
Snap for 11185025 from 97bd3fdea42e0b6fab817b63e67099ee5ff04dbe to mainline-networking-releaseaml_net_341411030android14-mainline-networking-release
Change-Id: Ie4af5defba1c5a3958cacd1fd6c2c14caa01147f
37 files changed, 1090 insertions, 1081 deletions
diff --git a/apps/CtsVerifier/jni/midi/MidiTestManager.cpp b/apps/CtsVerifier/jni/midi/MidiTestManager.cpp index 939fe39b888..c5d30cc1176 100644 --- a/apps/CtsVerifier/jni/midi/MidiTestManager.cpp +++ b/apps/CtsVerifier/jni/midi/MidiTestManager.cpp @@ -17,6 +17,7 @@ #include <pthread.h> #include <unistd.h> #include <stdio.h> +#include <chrono> #define TAG "MidiTestManager" #include <android/log.h> @@ -32,6 +33,7 @@ static const bool DEBUG = true; static const bool DEBUG_MIDIDATA = true; static const int MAX_PACKET_SIZE = 1024; +static const int TIMEOUT_SECONDS = 5; // // MIDI Messages @@ -130,7 +132,7 @@ MidiTestManager::MidiTestManager() : mTestModuleObj(NULL), mReceiveStreamPos(0), mMidiSendPort(NULL), mMidiReceivePort(NULL), - mTestMsgs(NULL), mNumTestMsgs(0), + mTestMsgs(0), mNumTestMsgs(0), mThrottleData(false) {} @@ -154,6 +156,22 @@ void MidiTestManager::jniSetup(JNIEnv* env) { } } +bool MidiTestManager::setupMessages() { + mNumTestMsgs = 7; + mTestMsgs.resize(mNumTestMsgs); + + if (!mTestMsgs[0].set(msg0, sizeof(msg0)) || + !mTestMsgs[1].set(msg1, sizeof(msg1)) || + !mTestMsgs[2].setSysExMessage(30) || + !mTestMsgs[3].setSysExMessage(6) || + !mTestMsgs[4].setSysExMessage(120) || + !mTestMsgs[5].setTwoSysExMessage(5, 13) || + !mTestMsgs[6].setSysExMessage(340)) { + return false; + } + return true; +} + void MidiTestManager::buildMatchStream() { mMatchStream.clear(); for(int byteIndex = 0; byteIndex < sizeof(warmupMsg); byteIndex++) { @@ -260,16 +278,25 @@ int MidiTestManager::matchStream(uint8_t* bytes, int count) { #define THROTTLE_PERIOD_MS 20 #define THROTTLE_MAX_PACKET_SIZE 15 +/** + * Send a number of bytes. + * + * Returns the number of sent bytes on success or negative error code on failure. + * + */ int portSend(AMidiInputPort* sendPort, uint8_t* msg, int length, bool throttle) { int numSent = 0; if (throttle) { for(int index = 0; index < length; index += THROTTLE_MAX_PACKET_SIZE) { int packetSize = std::min(length - index, THROTTLE_MAX_PACKET_SIZE); - AMidiInputPort_send(sendPort, msg + index, packetSize); + int curSent = AMidiInputPort_send(sendPort, msg + index, packetSize); + if (curSent < 0) { + return curSent; + } + numSent += curSent; usleep(THROTTLE_PERIOD_MS * 1000); } - numSent = length; } else { numSent = AMidiInputPort_send(sendPort, msg, length); } @@ -278,7 +305,7 @@ int portSend(AMidiInputPort* sendPort, uint8_t* msg, int length, bool throttle) /** * Writes out the list of MIDI messages to the output port. - * Returns total number of bytes sent. + * Returns total number of bytes sent or negative error code. */ int MidiTestManager::sendMessages() { if (DEBUG) { @@ -301,6 +328,10 @@ int MidiTestManager::sendMessages() { ssize_t numSent = portSend(mMidiSendPort, mTestMsgs[msgIndex].mMsgBytes, mTestMsgs[msgIndex].mNumMsgBytes, mThrottleData); + if (numSent < 0) { + ALOGE("sendMessages(): Send failed. index: %d, error: %zd", msgIndex, numSent); + return numSent; + } totalSent += numSent; } @@ -320,6 +351,9 @@ int MidiTestManager::ProcessInput() { int32_t opCode; size_t numBytesReceived; int64_t timeStamp; + + auto startTime = std::chrono::system_clock::now(); + while (true) { // AMidiOutputPort_receive is non-blocking, so let's not burn up the CPU unnecessarily usleep(2000); @@ -365,6 +399,16 @@ int MidiTestManager::ProcessInput() { return testResult; } } + + auto currentTime = std::chrono::system_clock::now(); + std::chrono::duration<double> elapsedSeconds = currentTime - startTime; + if (elapsedSeconds.count() > TIMEOUT_SECONDS) { + testResult = TESTSTATUS_FAILED_TIMEOUT; + if (DEBUG) { + ALOGE("---- TESTSTATUS_FAILED_TIMEOUT"); + } + return testResult; + } } return testResult; @@ -414,8 +458,15 @@ bool MidiTestManager::RunTest(jobject testModuleObj, AMidiDevice* sendDevice, mJvm->AttachCurrentThread(&env, NULL); if (env == NULL) { EndTest(TESTSTATUS_FAILED_JNI); + return false; // bail } + if (!setupMessages()) { + EndTest(TESTSTATUS_FAILED_SETUP); + return false; // bail + } + buildMatchStream(); + mTestModuleObj = env->NewGlobalRef(testModuleObj); // Call StartWriting first because StartReading starts a thread. @@ -425,26 +476,16 @@ bool MidiTestManager::RunTest(jobject testModuleObj, AMidiDevice* sendDevice, return false; // bail } - // setup messages - delete[] mTestMsgs; - mNumTestMsgs = 7; - mTestMsgs = new TestMessage[mNumTestMsgs]; + int bytesSent = sendMessages(); + void* threadRetval = (void*)TESTSTATUS_NOTRUN; + int status = pthread_join(readThread, &threadRetval); - if (!mTestMsgs[0].set(msg0, sizeof(msg0)) || - !mTestMsgs[1].set(msg1, sizeof(msg1)) || - !mTestMsgs[2].setSysExMessage(30) || - !mTestMsgs[3].setSysExMessage(6) || - !mTestMsgs[4].setSysExMessage(120) || - !mTestMsgs[5].setTwoSysExMessage(5, 13) || - !mTestMsgs[6].setSysExMessage(340)) { + // If send fails, the test should still wait for the receiver port to timeout to flush buffers. + if (bytesSent < 0) { + EndTest(TESTSTATUS_FAILED_SEND); return false; } - buildMatchStream(); - - sendMessages(); - void* threadRetval = (void*)TESTSTATUS_NOTRUN; - int status = pthread_join(readThread, &threadRetval); if (status != 0) { ALOGE("Failed to join readThread: %s (%d)", strerror(status), status); } diff --git a/apps/CtsVerifier/jni/midi/MidiTestManager.h b/apps/CtsVerifier/jni/midi/MidiTestManager.h index 0a3a213a2e7..ec6176e53f5 100644 --- a/apps/CtsVerifier/jni/midi/MidiTestManager.h +++ b/apps/CtsVerifier/jni/midi/MidiTestManager.h @@ -39,6 +39,7 @@ private: void buildMatchStream(); int matchStream(uint8_t* bytes, int count); + bool setupMessages(); int sendMessages(); jobject mTestModuleObj; @@ -53,7 +54,7 @@ private: AMidiOutputPort* mMidiReceivePort; // The array of messages to send/receive - TestMessage* mTestMsgs; + std::vector<TestMessage> mTestMsgs; int mNumTestMsgs; bool mThrottleData; @@ -70,6 +71,8 @@ private: static const int TESTSTATUS_FAILED_OVERRUN = 4; static const int TESTSTATUS_FAILED_DEVICE = 5; static const int TESTSTATUS_FAILED_JNI = 6; + static const int TESTSTATUS_FAILED_SETUP = 7; + static const int TESTSTATUS_FAILED_SEND = 8; bool StartReading(AMidiDevice* nativeReadDevice); bool StartWriting(AMidiDevice* nativeWriteDevice); diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml index d7cd7856239..d2000b7f7fc 100644 --- a/apps/CtsVerifier/res/values/strings.xml +++ b/apps/CtsVerifier/res/values/strings.xml @@ -5610,6 +5610,8 @@ You should be prompted to select credentials; choose the ones you just installed <string name="midiFailedOverrunLbl">Failed - Data Overrun.</string> <string name="midiFailedDeviceLbl">Failed - Device Error.</string> <string name="midiFailedJNILbl">Failed - JNI Error.</string> + <string name="midiFailedSetupLbl">Failed - Error in Setup.</string> + <string name="midiFailedSendLbl">Failed - Error during Send.</string> <!-- Audio general text --> <string name="audio_wired_exists">Does this device support wired USB or Analog audio peripherals?</string> diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/MidiTestActivityBase.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/MidiTestActivityBase.java index ef603a7fd66..606a7776b19 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/MidiTestActivityBase.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/MidiTestActivityBase.java @@ -306,6 +306,12 @@ public abstract class MidiTestActivityBase case MidiTestModule.TESTSTATUS_FAILED_JNI: return appResources.getString(R.string.midiFailedJNILbl); + case MidiTestModule.TESTSTATUS_FAILED_SETUP: + return appResources.getString(R.string.midiFailedSetupLbl); + + case MidiTestModule.TESTSTATUS_FAILED_SEND: + return appResources.getString(R.string.midiFailedSendLbl); + default: return "Unknown Test Status."; } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMidiAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMidiAudioActivity.java index 0ff6573f11b..7466dd33dd5 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMidiAudioActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMidiAudioActivity.java @@ -274,6 +274,12 @@ public class UsbMidiAudioActivity extends USBAudioPeripheralPlayerActivity { case MidiTestModule.TESTSTATUS_FAILED_JNI: return appResources.getString(R.string.midiFailedJNILbl); + case MidiTestModule.TESTSTATUS_FAILED_SETUP: + return appResources.getString(R.string.midiFailedSetupLbl); + + case MidiTestModule.TESTSTATUS_FAILED_SEND: + return appResources.getString(R.string.midiFailedSendLbl); + default: return "Unknown Test Status."; } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/midilib/MidiTestModule.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/midilib/MidiTestModule.java index a140676b9da..22692864e9a 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/midilib/MidiTestModule.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/midilib/MidiTestModule.java @@ -37,6 +37,8 @@ public abstract class MidiTestModule { public static final int TESTSTATUS_FAILED_OVERRUN = 4; public static final int TESTSTATUS_FAILED_DEVICE = 5; public static final int TESTSTATUS_FAILED_JNI = 6; + public static final int TESTSTATUS_FAILED_SETUP = 7; + public static final int TESTSTATUS_FAILED_SEND = 8; public static final int TESTID_NONE = 0; public static final int TESTID_USBLOOPBACK = 1; diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java index 2146a8558d0..78b3ae8c247 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java @@ -50,12 +50,15 @@ import androidx.test.uiautomator.UiObjectNotFoundException; import androidx.test.uiautomator.UiSelector; import com.android.bedstead.harrier.BedsteadJUnit4; +import com.android.bedstead.harrier.DeviceState; import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile; import com.android.modules.utils.build.SdkLevel; import org.junit.After; import org.junit.Assume; import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -77,6 +80,9 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest { @Nullable private static DeviceStatePreserver sDeviceStatePreserver; + @ClassRule @Rule + public static final DeviceState sDeviceState = new DeviceState(); + @Before public void setUp() throws Exception { super.setUp(); @@ -145,6 +151,7 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest { @RequireRunOnWorkProfile @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testSettingsLaunchedInPersonalProfile_WorkEnabled() throws Exception { + mSettingsIntent.putExtra(EXTRA_TAB_USER_ID, sDeviceState.initialUser().id()); launchSettingsActivityWithRetry(/* retryCount */ 3, /* backoffSeedInMillis */ 500); verifySettingsActivityIsVisible(); diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDisplayProxyTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDisplayProxyTest.java index 60c00220bec..4306fdc3494 100644 --- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDisplayProxyTest.java +++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDisplayProxyTest.java @@ -105,7 +105,6 @@ import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.SparseArray; -import android.util.TypedValue; import android.view.Display; import android.view.InputDevice; import android.view.KeyEvent; @@ -204,8 +203,10 @@ public class AccessibilityDisplayProxyTest { private static final String SEPARATE_PROCESS_PACKAGE_NAME = "foo.bar.proxy"; private static final String SEPARATE_PROCESS_ACTIVITY = ".NonProxySeparateAppActivity"; - - private static final float MIN_SCREEN_WIDTH_MM = 40.0f; + public static final int VIRTUAL_DISPLAY_WIDTH = 100; + // Minimum screen width for supporting taps. This is more arbitrary since clicking or + // tapping requires a single point. We use half the virtual display width. + private static final int MIN_SCREEN_WIDTH_TAP_PX = VIRTUAL_DISPLAY_WIDTH / 2; private static final int TEST_SYSTEM_ACTION_ID = 1000; public static final String INSTRUMENTED_STREAM_ROLE_PACKAGE_NAME = "android.accessibilityservice.cts"; @@ -583,8 +584,7 @@ public class AccessibilityDisplayProxyTest { WindowManager.class); final DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getRealMetrics(metrics); - assumeTrue(areaOfActivityWindowOnDisplay.width() > TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_MM, MIN_SCREEN_WIDTH_MM, metrics)); + assumeTrue(areaOfActivityWindowOnDisplay.width() > MIN_SCREEN_WIDTH_TAP_PX); sUiAutomation.executeAndWaitForEvent(() -> { final int xOnScreen = areaOfActivityWindowOnDisplay.centerX(); @@ -1508,7 +1508,8 @@ public class AccessibilityDisplayProxyTest { mFakeAssociationRule.getAssociationInfo().getId(), DEFAULT_VIRTUAL_DEVICE_PARAMS); // Values taken from StreamedAppClipboardTest - mImageReader = ImageReader.newInstance(/* width= */ 100, /* height= */ 100, + mImageReader = ImageReader.newInstance(/* width= */ VIRTUAL_DISPLAY_WIDTH, + /* height= */ 100, PixelFormat.RGBA_8888, /* maxImages= */ 1); display = mVirtualDevice.createVirtualDisplay( /* width= */ mImageReader.getWidth(), diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java index dfbaf860ef4..a0dfc3d8543 100644 --- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java +++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java @@ -295,7 +295,52 @@ public class GenericDocumentCtsTest { + " }\n" + "}"; - assertThat(documentString).isEqualTo(expectedString); + String[] lines = expectedString.split("\n"); + for (String line : lines) { + assertThat(documentString).contains(line); + } + } + + @Test + public void testDocumentEmptyProperties_toString() { + GenericDocument document = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace", "id1", "schemaType1") + .setCreationTimestampMillis(1L) + .setScore(1) + .setTtlMillis(1L) + .setPropertyString("stringKey1") + .setPropertyBytes("bytesKey1") + .setPropertyLong("longKey1") + .setPropertyDouble("doubleKey1") + .setPropertyBoolean("booleanKey1") + .setPropertyDocument("documentKey1") + .build(); + + String documentString = document.toString(); + + String expectedString = + "{\n" + + " namespace: \"namespace\",\n" + + " id: \"id1\",\n" + + " score: 1,\n" + + " schemaType: \"schemaType1\",\n" + + " creationTimestampMillis: 1,\n" + + " timeToLiveMillis: 1,\n" + + " properties: {\n" + + " \"booleanKey1\": [],\n" + + " \"bytesKey1\": [],\n" + + " \"documentKey1\": [],\n" + + " \"doubleKey1\": [],\n" + + " \"longKey1\": [],\n" + + " \"stringKey1\": []\n" + + " }\n" + + "}"; + + String[] lines = expectedString.split("\n"); + for (String line : lines) { + assertThat(documentString).contains(line); + } } @Test diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java index af38f5b6385..535278860cb 100644 --- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java +++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java @@ -938,38 +938,47 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().addFilterSchemas("TestAddObserver-Type").build(), EXECUTOR, observer); - - // Index a document - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas( - new AppSearchSchema.Builder("TestAddObserver-Type").build()) - .build()) - .get(); - GenericDocument document = - new GenericDocument.Builder<GenericDocument.Builder<?>>( - "namespace", "testAddObserver-id1", "TestAddObserver-Type") - .build(); - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder().addGenericDocuments(document).build())); - - // Make sure the notification was received. - observer.waitForNotificationCount(2); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - /*changedSchemaNames=*/ ImmutableSet.of("TestAddObserver-Type"))); - assertThat(observer.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - "TestAddObserver-Type", - /*changedDocumentIds=*/ ImmutableSet.of("testAddObserver-id1"))); + try { + // Index a document + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas( + new AppSearchSchema.Builder("TestAddObserver-Type") + .build()) + .build()) + .get(); + GenericDocument document = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace", "testAddObserver-id1", "TestAddObserver-Type") + .build(); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(document) + .build())); + + // Make sure the notification was received. + observer.waitForNotificationCount(2); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + /*changedSchemaNames=*/ ImmutableSet.of( + "TestAddObserver-Type"))); + assertThat(observer.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + "TestAddObserver-Type", + /*changedDocumentIds=*/ ImmutableSet.of( + "testAddObserver-id1"))); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test @@ -1009,94 +1018,102 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().addFilterSchemas(AppSearchEmail.SCHEMA_TYPE).build(), EXECUTOR, emailObserver); + try { + // Make sure everything is empty + assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); + assertThat(unfilteredObserver.getDocumentChanges()).isEmpty(); + assertThat(emailObserver.getSchemaChanges()).isEmpty(); + assertThat(emailObserver.getDocumentChanges()).isEmpty(); + + // Index some documents + AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); + GenericDocument gift1 = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace2", "id2", "Gift") + .build(); - // Make sure everything is empty - assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); - assertThat(unfilteredObserver.getDocumentChanges()).isEmpty(); - assertThat(emailObserver.getSchemaChanges()).isEmpty(); - assertThat(emailObserver.getDocumentChanges()).isEmpty(); - - // Index some documents - AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); - GenericDocument gift1 = - new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace2", "id2", "Gift") - .build(); - - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder().addGenericDocuments(email1).build())); - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder() - .addGenericDocuments(email1, gift1) - .build())); - checkIsBatchResultSuccess( - mDb2.putAsync( - new PutDocumentsRequest.Builder().addGenericDocuments(email1).build())); - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder().addGenericDocuments(gift1).build())); - - // Make sure the notification was received. - unfilteredObserver.waitForNotificationCount(5); - emailObserver.waitForNotificationCount(3); - - assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); - assertThat(unfilteredObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id2")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id2"))); - - // Check the filtered observer - assertThat(emailObserver.getSchemaChanges()).isEmpty(); - assertThat(emailObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1"))); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder().addGenericDocuments(email1).build())); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(email1, gift1) + .build())); + checkIsBatchResultSuccess( + mDb2.putAsync( + new PutDocumentsRequest.Builder().addGenericDocuments(email1).build())); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder().addGenericDocuments(gift1).build())); + + // Make sure the notification was received. + unfilteredObserver.waitForNotificationCount(5); + emailObserver.waitForNotificationCount(3); + + assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); + assertThat(unfilteredObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id2")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id2"))); + + // Check the filtered observer + assertThat(emailObserver.getSchemaChanges()).isEmpty(); + assertThat(emailObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1"))); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), emailObserver); + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), unfilteredObserver); + } } @Test @@ -1134,102 +1151,114 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().addFilterSchemas(AppSearchEmail.SCHEMA_TYPE).build(), EXECUTOR, emailObserver); + try { + // Make sure everything is empty + assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); + assertThat(unfilteredObserver.getDocumentChanges()).isEmpty(); + assertThat(emailObserver.getSchemaChanges()).isEmpty(); + assertThat(emailObserver.getDocumentChanges()).isEmpty(); + + // Index some documents + AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); + GenericDocument gift1 = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace2", "id2", "Gift") + .build(); - // Make sure everything is empty - assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); - assertThat(unfilteredObserver.getDocumentChanges()).isEmpty(); - assertThat(emailObserver.getSchemaChanges()).isEmpty(); - assertThat(emailObserver.getDocumentChanges()).isEmpty(); - - // Index some documents - AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); - GenericDocument gift1 = - new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace2", "id2", "Gift") - .build(); - - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder().addGenericDocuments(email1).build())); - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder() - .addGenericDocuments(email1, gift1) - .build())); - checkIsBatchResultSuccess( - mDb2.putAsync( - new PutDocumentsRequest.Builder() - .addGenericDocuments(email1, gift1) - .build())); - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder().addGenericDocuments(gift1).build())); - - // Register the second observer - mGlobalSearchSession.registerObserverCallback( - mContext.getPackageName(), - new ObserverSpec.Builder().build(), - EXECUTOR, - unfilteredObserver); - - // Remove some of the documents. - checkIsBatchResultSuccess( - mDb1.removeAsync( - new RemoveByDocumentIdRequest.Builder("namespace").addIds("id1").build())); - checkIsBatchResultSuccess( - mDb2.removeAsync( - new RemoveByDocumentIdRequest.Builder("namespace2").addIds("id2").build())); - - // Make sure the notification was received. emailObserver should have seen: - // +db1:email, +db1:email, +db2:email, -db1:email. - // unfilteredObserver (registered later) should have seen: - // -db1:email, -db2:gift - emailObserver.waitForNotificationCount(4); - unfilteredObserver.waitForNotificationCount(2); - - assertThat(emailObserver.getSchemaChanges()).isEmpty(); - assertThat(emailObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1"))); - - // Check unfilteredObserver - assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); - assertThat(unfilteredObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id2"))); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder().addGenericDocuments(email1).build())); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(email1, gift1) + .build())); + checkIsBatchResultSuccess( + mDb2.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(email1, gift1) + .build())); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder().addGenericDocuments(gift1).build())); + + // Register the second observer + mGlobalSearchSession.registerObserverCallback( + mContext.getPackageName(), + new ObserverSpec.Builder().build(), + EXECUTOR, + unfilteredObserver); + + // Remove some of the documents. + checkIsBatchResultSuccess( + mDb1.removeAsync( + new RemoveByDocumentIdRequest.Builder("namespace") + .addIds("id1") + .build())); + checkIsBatchResultSuccess( + mDb2.removeAsync( + new RemoveByDocumentIdRequest.Builder("namespace2") + .addIds("id2") + .build())); + + // Make sure the notification was received. emailObserver should have seen: + // +db1:email, +db1:email, +db2:email, -db1:email. + // unfilteredObserver (registered later) should have seen: + // -db1:email, -db2:gift + emailObserver.waitForNotificationCount(4); + unfilteredObserver.waitForNotificationCount(2); + + assertThat(emailObserver.getSchemaChanges()).isEmpty(); + assertThat(emailObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1"))); + + // Check unfilteredObserver + assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); + assertThat(unfilteredObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id2"))); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), emailObserver); + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), unfilteredObserver); + } } @Test @@ -1290,67 +1319,74 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().addFilterSchemas(AppSearchEmail.SCHEMA_TYPE).build(), EXECUTOR, emailObserver); - - // Make sure everything is empty - assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); - assertThat(unfilteredObserver.getDocumentChanges()).isEmpty(); - assertThat(emailObserver.getSchemaChanges()).isEmpty(); - assertThat(emailObserver.getDocumentChanges()).isEmpty(); - - // Remove "cat" emails in db1 and all types in db2 - mDb1.removeAsync( - "cat", - new SearchSpec.Builder() - .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE) - .build()) - .get(); - mDb2.removeAsync("", new SearchSpec.Builder().build()).get(); - - // Make sure the notification was received. UnfilteredObserver should have seen: - // -db1:id2, -db2:id1, -db2:id2, -db2:id3 - // emailObserver should have seen: - // -db1:id2, -db2:id1, -db2:id2 - unfilteredObserver.waitForNotificationCount(3); - emailObserver.waitForNotificationCount(2); - - assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); - assertThat(unfilteredObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id2")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1", "id2")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id3"))); - - // Check emailObserver - assertThat(emailObserver.getSchemaChanges()).isEmpty(); - assertThat(emailObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id2")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_2, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1", "id2"))); + try { + // Make sure everything is empty + assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); + assertThat(unfilteredObserver.getDocumentChanges()).isEmpty(); + assertThat(emailObserver.getSchemaChanges()).isEmpty(); + assertThat(emailObserver.getDocumentChanges()).isEmpty(); + + // Remove "cat" emails in db1 and all types in db2 + mDb1.removeAsync( + "cat", + new SearchSpec.Builder() + .addFilterSchemas(AppSearchEmail.SCHEMA_TYPE) + .build()) + .get(); + mDb2.removeAsync("", new SearchSpec.Builder().build()).get(); + + // Make sure the notification was received. UnfilteredObserver should have seen: + // -db1:id2, -db2:id1, -db2:id2, -db2:id3 + // emailObserver should have seen: + // -db1:id2, -db2:id1, -db2:id2 + unfilteredObserver.waitForNotificationCount(3); + emailObserver.waitForNotificationCount(2); + + assertThat(unfilteredObserver.getSchemaChanges()).isEmpty(); + assertThat(unfilteredObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id2")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1", "id2")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id3"))); + + // Check emailObserver + assertThat(emailObserver.getSchemaChanges()).isEmpty(); + assertThat(emailObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id2")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_2, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1", "id2"))); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), emailObserver); + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), unfilteredObserver); + } } @Test @@ -1386,36 +1422,41 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().addFilterSchemas(AppSearchEmail.SCHEMA_TYPE).build(), EXECUTOR, observer); + try { + // Index one email and one gift + AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); + GenericDocument gift1 = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace2", "id3", "Gift") + .build(); - // Index one email and one gift - AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); - GenericDocument gift1 = - new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace2", "id3", "Gift") - .build(); - - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder() - .addGenericDocuments(email1, gift1) - .build())); - - // Make sure the same observer received both values - observer.waitForNotificationCount(2); - assertThat(observer.getSchemaChanges()).isEmpty(); - assertThat(observer.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id3"))); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(email1, gift1) + .build())); + + // Make sure the same observer received both values + observer.waitForNotificationCount(2); + assertThat(observer.getSchemaChanges()).isEmpty(); + assertThat(observer.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id3"))); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test @@ -1463,100 +1504,109 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().build(), EXECUTOR, permanentObserver); + try { + // Make sure everything is empty + assertThat(temporaryObserver.getSchemaChanges()).isEmpty(); + assertThat(temporaryObserver.getDocumentChanges()).isEmpty(); + assertThat(permanentObserver.getSchemaChanges()).isEmpty(); + assertThat(permanentObserver.getDocumentChanges()).isEmpty(); + + // Index some documents + AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); + AppSearchEmail email2 = + new AppSearchEmail.Builder("namespace", "id2").setBody("caterpillar").build(); + GenericDocument gift1 = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace2", "id3", "Gift") + .build(); + GenericDocument gift2 = + new GenericDocument.Builder<GenericDocument.Builder<?>>( + "namespace3", "id4", "Gift") + .build(); - // Make sure everything is empty - assertThat(temporaryObserver.getSchemaChanges()).isEmpty(); - assertThat(temporaryObserver.getDocumentChanges()).isEmpty(); - assertThat(permanentObserver.getSchemaChanges()).isEmpty(); - assertThat(permanentObserver.getDocumentChanges()).isEmpty(); - - // Index some documents - AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build(); - AppSearchEmail email2 = - new AppSearchEmail.Builder("namespace", "id2").setBody("caterpillar").build(); - GenericDocument gift1 = - new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace2", "id3", "Gift") - .build(); - GenericDocument gift2 = - new GenericDocument.Builder<GenericDocument.Builder<?>>("namespace3", "id4", "Gift") - .build(); - - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder() - .addGenericDocuments(email1, gift1) - .build())); - - // Make sure the notifications were received. - temporaryObserver.waitForNotificationCount(2); - permanentObserver.waitForNotificationCount(2); - - List<DocumentChangeInfo> expectedChangesOrig = - ImmutableList.of( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id3"))); - assertThat(temporaryObserver.getSchemaChanges()).isEmpty(); - assertThat(temporaryObserver.getDocumentChanges()) - .containsExactlyElementsIn(expectedChangesOrig); - assertThat(permanentObserver.getSchemaChanges()).isEmpty(); - assertThat(permanentObserver.getDocumentChanges()) - .containsExactlyElementsIn(expectedChangesOrig); - - // Unregister temporaryObserver - mGlobalSearchSession.unregisterObserverCallback( - mContext.getPackageName(), temporaryObserver); - - // Index some more documents - checkIsBatchResultSuccess( - mDb1.putAsync( - new PutDocumentsRequest.Builder() - .addGenericDocuments(email2, gift2) - .build())); - - // Only the permanent observer should have received this - permanentObserver.waitForNotificationCount(4); - temporaryObserver.waitForNotificationCount(2); - - assertThat(permanentObserver.getSchemaChanges()).isEmpty(); - assertThat(permanentObserver.getDocumentChanges()) - .containsExactly( - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id1")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace2", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id3")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace", - AppSearchEmail.SCHEMA_TYPE, - /*changedDocumentIds=*/ ImmutableSet.of("id2")), - new DocumentChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - "namespace3", - "Gift", - /*changedDocumentIds=*/ ImmutableSet.of("id4"))); - assertThat(temporaryObserver.getSchemaChanges()).isEmpty(); - assertThat(temporaryObserver.getDocumentChanges()) - .containsExactlyElementsIn(expectedChangesOrig); + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(email1, gift1) + .build())); + + // Make sure the notifications were received. + temporaryObserver.waitForNotificationCount(2); + permanentObserver.waitForNotificationCount(2); + + List<DocumentChangeInfo> expectedChangesOrig = + ImmutableList.of( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id3"))); + assertThat(temporaryObserver.getSchemaChanges()).isEmpty(); + assertThat(temporaryObserver.getDocumentChanges()) + .containsExactlyElementsIn(expectedChangesOrig); + assertThat(permanentObserver.getSchemaChanges()).isEmpty(); + assertThat(permanentObserver.getDocumentChanges()) + .containsExactlyElementsIn(expectedChangesOrig); + + // Unregister temporaryObserver + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), temporaryObserver); + + // Index some more documents + checkIsBatchResultSuccess( + mDb1.putAsync( + new PutDocumentsRequest.Builder() + .addGenericDocuments(email2, gift2) + .build())); + + // Only the permanent observer should have received this + permanentObserver.waitForNotificationCount(4); + temporaryObserver.waitForNotificationCount(2); + + assertThat(permanentObserver.getSchemaChanges()).isEmpty(); + assertThat(permanentObserver.getDocumentChanges()) + .containsExactly( + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id1")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace2", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id3")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace", + AppSearchEmail.SCHEMA_TYPE, + /*changedDocumentIds=*/ ImmutableSet.of("id2")), + new DocumentChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + "namespace3", + "Gift", + /*changedDocumentIds=*/ ImmutableSet.of("id4"))); + assertThat(temporaryObserver.getSchemaChanges()).isEmpty(); + assertThat(temporaryObserver.getDocumentChanges()) + .containsExactlyElementsIn(expectedChangesOrig); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), temporaryObserver); + mGlobalSearchSession.unregisterObserverCallback( + mContext.getPackageName(), permanentObserver); + } } @Test @@ -1661,42 +1711,48 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().build(), EXECUTOR, observer); - - // Add a schema type - assertThat(observer.getSchemaChanges()).isEmpty(); - assertThat(observer.getDocumentChanges()).isEmpty(); - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas(new AppSearchSchema.Builder("Type1").build()) - .build()) - .get(); - - observer.waitForNotificationCount(1); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), DB_NAME_1, ImmutableSet.of("Type1"))); - assertThat(observer.getDocumentChanges()).isEmpty(); - - // Add two more schema types without touching the existing one - observer.clear(); - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas( - new AppSearchSchema.Builder("Type1").build(), - new AppSearchSchema.Builder("Type2").build(), - new AppSearchSchema.Builder("Type3").build()) - .build()) - .get(); - - observer.waitForNotificationCount(1); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), - DB_NAME_1, - ImmutableSet.of("Type2", "Type3"))); - assertThat(observer.getDocumentChanges()).isEmpty(); + try { + // Add a schema type + assertThat(observer.getSchemaChanges()).isEmpty(); + assertThat(observer.getDocumentChanges()).isEmpty(); + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas(new AppSearchSchema.Builder("Type1").build()) + .build()) + .get(); + + observer.waitForNotificationCount(1); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + ImmutableSet.of("Type1"))); + assertThat(observer.getDocumentChanges()).isEmpty(); + + // Add two more schema types without touching the existing one + observer.clear(); + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas( + new AppSearchSchema.Builder("Type1").build(), + new AppSearchSchema.Builder("Type2").build(), + new AppSearchSchema.Builder("Type3").build()) + .build()) + .get(); + + observer.waitForNotificationCount(1); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + ImmutableSet.of("Type2", "Type3"))); + assertThat(observer.getDocumentChanges()).isEmpty(); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test @@ -1723,20 +1779,27 @@ public abstract class GlobalSearchSessionCtsTestBase { EXECUTOR, observer); - // Remove Type2 - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas(new AppSearchSchema.Builder("Type1").build()) - .setForceOverride(true) - .build()) - .get(); - - observer.waitForNotificationCount(1); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), DB_NAME_1, ImmutableSet.of("Type2"))); - assertThat(observer.getDocumentChanges()).isEmpty(); + try { + // Remove Type2 + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas(new AppSearchSchema.Builder("Type1").build()) + .setForceOverride(true) + .build()) + .get(); + + observer.waitForNotificationCount(1); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + ImmutableSet.of("Type2"))); + assertThat(observer.getDocumentChanges()).isEmpty(); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test @@ -1771,48 +1834,57 @@ public abstract class GlobalSearchSessionCtsTestBase { EXECUTOR, observer); - // Update the schema, but don't make any actual changes - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas( - new AppSearchSchema.Builder("Type1").build(), - new AppSearchSchema.Builder("Type2") - .addProperty( - new AppSearchSchema.BooleanPropertyConfig - .Builder("booleanProp") - .setCardinality( - PropertyConfig - .CARDINALITY_REQUIRED) - .build()) - .build()) - .build()) + try { + // Update the schema, but don't make any actual changes + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas( + new AppSearchSchema.Builder("Type1").build(), + new AppSearchSchema.Builder("Type2") + .addProperty( + new AppSearchSchema + .BooleanPropertyConfig + .Builder("booleanProp") + .setCardinality( + PropertyConfig + .CARDINALITY_REQUIRED) + .build()) + .build()) + .build()) .get(); - // Now update the schema again, but this time actually make a change (cardinality of the - // property) - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas( - new AppSearchSchema.Builder("Type1").build(), - new AppSearchSchema.Builder("Type2") - .addProperty( - new AppSearchSchema.BooleanPropertyConfig - .Builder("booleanProp") - .setCardinality( - PropertyConfig - .CARDINALITY_OPTIONAL) - .build()) - .build()) - .build()) + // Now update the schema again, but this time actually make a change (cardinality of the + // property) + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas( + new AppSearchSchema.Builder("Type1").build(), + new AppSearchSchema.Builder("Type2") + .addProperty( + new AppSearchSchema + .BooleanPropertyConfig + .Builder("booleanProp") + .setCardinality( + PropertyConfig + .CARDINALITY_OPTIONAL) + .build()) + .build()) + .build()) .get(); - // Dispatch notifications - observer.waitForNotificationCount(1); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), DB_NAME_1, ImmutableSet.of("Type2"))); - assertThat(observer.getDocumentChanges()).isEmpty(); + // Dispatch notifications + observer.waitForNotificationCount(1); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + ImmutableSet.of("Type2"))); + assertThat(observer.getDocumentChanges()).isEmpty(); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test @@ -1824,28 +1896,27 @@ public abstract class GlobalSearchSessionCtsTestBase { // Add a schema mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas( - new AppSearchSchema.Builder("Type1") - .addProperty( - new AppSearchSchema.BooleanPropertyConfig - .Builder("booleanProp") - .setCardinality( - PropertyConfig - .CARDINALITY_REQUIRED) - .build()) - .build(), - new AppSearchSchema.Builder("Type2") - .addProperty( - new AppSearchSchema.BooleanPropertyConfig - .Builder("booleanProp") - .setCardinality( - PropertyConfig - .CARDINALITY_REQUIRED) - .build()) - .build()) + new SetSchemaRequest.Builder() + .addSchemas( + new AppSearchSchema.Builder("Type1") + .addProperty( + new AppSearchSchema.BooleanPropertyConfig + .Builder("booleanProp") + .setCardinality( + PropertyConfig + .CARDINALITY_REQUIRED) .build()) - .get(); + .build(), + new AppSearchSchema.Builder("Type2") + .addProperty( + new AppSearchSchema.BooleanPropertyConfig + .Builder("booleanProp") + .setCardinality( + PropertyConfig + .CARDINALITY_REQUIRED) + .build()) + .build()) + .build()).get(); // Register an observer that only listens for Type2 TestObserverCallback observer = new TestObserverCallback(); @@ -1854,38 +1925,46 @@ public abstract class GlobalSearchSessionCtsTestBase { new ObserverSpec.Builder().addFilterSchemas("Type2").build(), EXECUTOR, observer); - - // Update both types of the schema (changed cardinalities) - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .addSchemas( - new AppSearchSchema.Builder("Type1") - .addProperty( - new AppSearchSchema.BooleanPropertyConfig - .Builder("booleanProp") - .setCardinality( - PropertyConfig - .CARDINALITY_OPTIONAL) - .build()) - .build(), - new AppSearchSchema.Builder("Type2") - .addProperty( - new AppSearchSchema.BooleanPropertyConfig - .Builder("booleanProp") - .setCardinality( - PropertyConfig - .CARDINALITY_OPTIONAL) - .build()) - .build()) - .build()) + try { + // Update both types of the schema (changed cardinalities) + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .addSchemas( + new AppSearchSchema.Builder("Type1") + .addProperty( + new AppSearchSchema + .BooleanPropertyConfig + .Builder("booleanProp") + .setCardinality( + PropertyConfig + .CARDINALITY_OPTIONAL) + .build()) + .build(), + new AppSearchSchema.Builder("Type2") + .addProperty( + new AppSearchSchema + .BooleanPropertyConfig + .Builder("booleanProp") + .setCardinality( + PropertyConfig + .CARDINALITY_OPTIONAL) + .build()) + .build()) + .build()) .get(); - observer.waitForNotificationCount(1); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), DB_NAME_1, ImmutableSet.of("Type2"))); - assertThat(observer.getDocumentChanges()).isEmpty(); + observer.waitForNotificationCount(1); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + ImmutableSet.of("Type2"))); + assertThat(observer.getDocumentChanges()).isEmpty(); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test @@ -1894,7 +1973,6 @@ public abstract class GlobalSearchSessionCtsTestBase { mDb1.getFeatures() .isFeatureSupported( Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK)); - // Add a schema with two types mDb1.setSchemaAsync( new SetSchemaRequest.Builder() @@ -1950,138 +2028,147 @@ public abstract class GlobalSearchSessionCtsTestBase { EXECUTOR, observer); - // Update both types of the schema with migration to a new property name - mDb1.setSchemaAsync( - new SetSchemaRequest.Builder() - .setVersion(2) - .addSchemas( - new AppSearchSchema.Builder("Type1") - .addProperty( - new AppSearchSchema.StringPropertyConfig - .Builder("strProp2") - .build()) - .build(), - new AppSearchSchema.Builder("Type2") - .addProperty( - new AppSearchSchema.LongPropertyConfig - .Builder("longProp2") - .build()) - .build()) - .setMigrator( - "Type1", - new Migrator() { - @Override - public boolean shouldMigrate( - int currentVersion, int finalVersion) { - assertThat(currentVersion).isEqualTo(1); - assertThat(finalVersion).isEqualTo(2); - return true; - } - - @NonNull - @Override - public GenericDocument onUpgrade( - int currentVersion, - int finalVersion, - @NonNull GenericDocument document) { - assertThat(currentVersion).isEqualTo(1); - assertThat(finalVersion).isEqualTo(2); - assertThat(document.getSchemaType()) - .isEqualTo("Type1"); - String[] prop = - document.getPropertyStringArray("strProp1"); - assertThat(prop).isNotNull(); - return new GenericDocument.Builder< - GenericDocument.Builder<?>>( - document.getNamespace(), - document.getId(), - document.getSchemaType()) - .setPropertyString("strProp2", prop) - .build(); - } - - @NonNull - @Override - public GenericDocument onDowngrade( - int currentVersion, - int finalVersion, - @NonNull GenericDocument document) { - // Doesn't happen in this test - throw new UnsupportedOperationException(); - } - }) - .setMigrator( - "Type2", - new Migrator() { - @Override - public boolean shouldMigrate( - int currentVersion, int finalVersion) { - assertThat(currentVersion).isEqualTo(1); - assertThat(finalVersion).isEqualTo(2); - return true; - } - - @NonNull - @Override - public GenericDocument onUpgrade( - int currentVersion, - int finalVersion, - @NonNull GenericDocument document) { - assertThat(currentVersion).isEqualTo(1); - assertThat(finalVersion).isEqualTo(2); - assertThat(document.getSchemaType()) - .isEqualTo("Type2"); - long[] prop = - document.getPropertyLongArray("longProp1"); - assertThat(prop).isNotNull(); - return new GenericDocument.Builder< - GenericDocument.Builder<?>>( - document.getNamespace(), - document.getId(), - document.getSchemaType()) - .setPropertyLong( - "longProp2", prop[0] + 1000) - .build(); - } - - @NonNull - @Override - public GenericDocument onDowngrade( - int currentVersion, - int finalVersion, - @NonNull GenericDocument document) { - // Doesn't happen in this test - throw new UnsupportedOperationException(); - } - }) - .build()) - .get(); - - // Make sure the test is valid by checking that migration actually occurred - AppSearchBatchResult<String, GenericDocument> getResponse = - mDb1.getByDocumentIdAsync( - new GetByDocumentIdRequest.Builder("namespace") - .addIds("t1id1", "t1id2", "t2id1", "t2id2") - .build()) - .get(); - assertThat(getResponse.isSuccess()).isTrue(); - assertThat(getResponse.getSuccesses().get("t1id1").getPropertyString("strProp2")) - .isEqualTo("t1id1 prop value"); - assertThat(getResponse.getSuccesses().get("t1id2").getPropertyString("strProp2")) - .isEqualTo("t1id2 prop value"); - assertThat(getResponse.getSuccesses().get("t2id1").getPropertyLong("longProp2")) - .isEqualTo(1041); - assertThat(getResponse.getSuccesses().get("t2id2").getPropertyLong("longProp2")) - .isEqualTo(1042); - - // Per the observer documentation, for schema migrations, individual document changes are - // not dispatched. Only SchemaChangeInfo is dispatched. - observer.waitForNotificationCount(1); - assertThat(observer.getSchemaChanges()) - .containsExactly( - new SchemaChangeInfo( - mContext.getPackageName(), DB_NAME_1, ImmutableSet.of("Type1"))); - assertThat(observer.getDocumentChanges()).isEmpty(); + try { + // Update both types of the schema with migration to a new property name + mDb1.setSchemaAsync( + new SetSchemaRequest.Builder() + .setVersion(2) + .addSchemas( + new AppSearchSchema.Builder("Type1") + .addProperty( + new AppSearchSchema.StringPropertyConfig + .Builder("strProp2") + .build()) + .build(), + new AppSearchSchema.Builder("Type2") + .addProperty( + new AppSearchSchema.LongPropertyConfig + .Builder("longProp2") + .build()) + .build()) + .setMigrator( + "Type1", + new Migrator() { + @Override + public boolean shouldMigrate( + int currentVersion, int finalVersion) { + assertThat(currentVersion).isEqualTo(1); + assertThat(finalVersion).isEqualTo(2); + return true; + } + + @NonNull + @Override + public GenericDocument onUpgrade( + int currentVersion, + int finalVersion, + @NonNull GenericDocument document) { + assertThat(currentVersion).isEqualTo(1); + assertThat(finalVersion).isEqualTo(2); + assertThat(document.getSchemaType()) + .isEqualTo("Type1"); + String[] prop = + document.getPropertyStringArray( + "strProp1"); + assertThat(prop).isNotNull(); + return new GenericDocument.Builder< + GenericDocument.Builder<?>>( + document.getNamespace(), + document.getId(), + document.getSchemaType()) + .setPropertyString("strProp2", prop) + .build(); + } + + @NonNull + @Override + public GenericDocument onDowngrade( + int currentVersion, + int finalVersion, + @NonNull GenericDocument document) { + // Doesn't happen in this test + throw new UnsupportedOperationException(); + } + }) + .setMigrator( + "Type2", + new Migrator() { + @Override + public boolean shouldMigrate( + int currentVersion, int finalVersion) { + assertThat(currentVersion).isEqualTo(1); + assertThat(finalVersion).isEqualTo(2); + return true; + } + + @NonNull + @Override + public GenericDocument onUpgrade( + int currentVersion, + int finalVersion, + @NonNull GenericDocument document) { + assertThat(currentVersion).isEqualTo(1); + assertThat(finalVersion).isEqualTo(2); + assertThat(document.getSchemaType()) + .isEqualTo("Type2"); + long[] prop = + document.getPropertyLongArray( + "longProp1"); + assertThat(prop).isNotNull(); + return new GenericDocument.Builder< + GenericDocument.Builder<?>>( + document.getNamespace(), + document.getId(), + document.getSchemaType()) + .setPropertyLong( + "longProp2", prop[0] + 1000) + .build(); + } + + @NonNull + @Override + public GenericDocument onDowngrade( + int currentVersion, + int finalVersion, + @NonNull GenericDocument document) { + // Doesn't happen in this test + throw new UnsupportedOperationException(); + } + }) + .build()) + .get(); + + // Make sure the test is valid by checking that migration actually occurred + AppSearchBatchResult<String, GenericDocument> getResponse = + mDb1.getByDocumentIdAsync( + new GetByDocumentIdRequest.Builder("namespace") + .addIds("t1id1", "t1id2", "t2id1", "t2id2") + .build()) + .get(); + assertThat(getResponse.isSuccess()).isTrue(); + assertThat(getResponse.getSuccesses().get("t1id1").getPropertyString("strProp2")) + .isEqualTo("t1id1 prop value"); + assertThat(getResponse.getSuccesses().get("t1id2").getPropertyString("strProp2")) + .isEqualTo("t1id2 prop value"); + assertThat(getResponse.getSuccesses().get("t2id1").getPropertyLong("longProp2")) + .isEqualTo(1041); + assertThat(getResponse.getSuccesses().get("t2id2").getPropertyLong("longProp2")) + .isEqualTo(1042); + + // Per the observer documentation, for schema migrations, individual document changes + // are not dispatched. Only SchemaChangeInfo is dispatched. + observer.waitForNotificationCount(1); + assertThat(observer.getSchemaChanges()) + .containsExactly( + new SchemaChangeInfo( + mContext.getPackageName(), + DB_NAME_1, + ImmutableSet.of("Type1"))); + assertThat(observer.getDocumentChanges()).isEmpty(); + } finally { + // Clean the observer + mGlobalSearchSession.unregisterObserverCallback(mContext.getPackageName(), observer); + } } @Test diff --git a/tests/appsearch/testutils/src/android/app/appsearch/testutil/FakeAppSearchConfig.java b/tests/appsearch/testutils/src/android/app/appsearch/testutil/FakeAppSearchConfig.java index e5794347c57..a914ccb3d1c 100644 --- a/tests/appsearch/testutils/src/android/app/appsearch/testutil/FakeAppSearchConfig.java +++ b/tests/appsearch/testutils/src/android/app/appsearch/testutil/FakeAppSearchConfig.java @@ -249,6 +249,18 @@ public final class FakeAppSearchConfig implements FrameworkAppSearchConfig { return DEFAULT_SHOULD_RETRIEVE_PARENT_INFO; } + @Override + public boolean getUseNewQualifiedIdJoinIndex() { + throwIfClosed(); + return DEFAULT_USE_NEW_QUALIFIED_ID_JOIN_INDEX; + } + + @Override + public boolean getBuildPropertyExistenceMetadataHits() { + throwIfClosed(); + return DEFAULT_BUILD_PROPERTY_EXISTENCE_METADATA_HITS; + } + private void throwIfClosed() { if (mIsClosed.get()) { throw new IllegalStateException( diff --git a/tests/appsearch/testutils/src/android/app/appsearch/testutil/MainlineFeaturesImpl.java b/tests/appsearch/testutils/src/android/app/appsearch/testutil/MainlineFeaturesImpl.java index a810d22df6c..71dc45f6cd2 100644 --- a/tests/appsearch/testutils/src/android/app/appsearch/testutil/MainlineFeaturesImpl.java +++ b/tests/appsearch/testutils/src/android/app/appsearch/testutil/MainlineFeaturesImpl.java @@ -18,7 +18,6 @@ package android.app.appsearch.testutil; import android.annotation.NonNull; import android.app.appsearch.Features; -import android.content.Context; import android.os.Build; /** @@ -80,7 +79,7 @@ public class MainlineFeaturesImpl implements Features { } @Override - public int getMaxIndexedProperties(@NonNull Context context) { + public int getMaxIndexedProperties() { return 64; } } diff --git a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AlwaysSupportedFeatures.java b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AlwaysSupportedFeatures.java index 3bf34aa9ae6..67164226108 100644 --- a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AlwaysSupportedFeatures.java +++ b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AlwaysSupportedFeatures.java @@ -18,7 +18,6 @@ package com.android.server.appsearch.external.localstorage; import android.annotation.NonNull; import android.app.appsearch.Features; -import android.content.Context; /** * An implementation of {@link Features}. This implementation always returns true. This is @@ -76,7 +75,7 @@ public class AlwaysSupportedFeatures implements Features { } @Override - public int getMaxIndexedProperties(@NonNull Context unused) { + public int getMaxIndexedProperties() { return 64; } } diff --git a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AppSearchConfigImpl.java b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AppSearchConfigImpl.java index a0d316e895e..ea6ff89b5d8 100644 --- a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AppSearchConfigImpl.java +++ b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/AppSearchConfigImpl.java @@ -114,6 +114,16 @@ public class AppSearchConfigImpl implements AppSearchConfig { } @Override + public boolean getUseNewQualifiedIdJoinIndex() { + return mIcingOptionsConfig.getUseNewQualifiedIdJoinIndex(); + } + + @Override + public boolean getBuildPropertyExistenceMetadataHits() { + return mIcingOptionsConfig.getBuildPropertyExistenceMetadataHits(); + } + + @Override public int getMaxDocumentSizeBytes() { return mLimitConfig.getMaxDocumentSizeBytes(); } diff --git a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/DefaultIcingOptionsConfig.java b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/DefaultIcingOptionsConfig.java index 12f77fb0691..6892bd15193 100644 --- a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/DefaultIcingOptionsConfig.java +++ b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/DefaultIcingOptionsConfig.java @@ -86,4 +86,14 @@ public class DefaultIcingOptionsConfig implements IcingOptionsConfig { public int getLiteIndexSortSize() { return DEFAULT_LITE_INDEX_SORT_SIZE; } + + @Override + public boolean getUseNewQualifiedIdJoinIndex() { + return DEFAULT_USE_NEW_QUALIFIED_ID_JOIN_INDEX; + } + + @Override + public boolean getBuildPropertyExistenceMetadataHits() { + return DEFAULT_BUILD_PROPERTY_EXISTENCE_METADATA_HITS; + } } diff --git a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/Features.java b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/Features.java index 59015b764b7..e16ceed9a43 100644 --- a/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/Features.java +++ b/tests/appsearch/testutils/src/android/app/appsearch/testutil/external/Features.java @@ -16,7 +16,6 @@ package android.app.appsearch; import android.annotation.NonNull; -import android.content.Context; /** * A class that encapsulates all features that are only supported in certain cases (e.g. only on @@ -183,8 +182,6 @@ public interface Features { * API level and AppSearch backend. * * <p>A property is defined as all values that are present at a particular path. - * - * @param context to check mainline module version, as support varies by module version. */ - int getMaxIndexedProperties(@NonNull Context context); + int getMaxIndexedProperties(); } diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp index adcb1700726..fba5b28c0f2 100644 --- a/tests/camera/Android.bp +++ b/tests/camera/Android.bp @@ -56,6 +56,7 @@ android_test { // Include both the 32 and 64 bit versions compile_multilib: "both", static_libs: [ + "collector-device-lib-platform", "compatibility-device-util-axt", "ctstestrunner-axt", "cts-hardware-lib", diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityCaptureCallbackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityCaptureCallbackTests.java index 82f1fb53660..c97ef5b435a 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityCaptureCallbackTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityCaptureCallbackTests.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import android.Manifest; +import android.os.Bundle; import android.platform.test.annotations.Presubmit; import com.android.compatibility.common.util.ApiTest; @@ -188,8 +189,8 @@ public class ActivityCaptureCallbackTests extends WindowManagerTestBase { } @Override - protected void onStart() { - super.onStart(); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); registerScreenCaptureCallback(Executors.newSingleThreadExecutor(), mCallback); } } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java index 09b253c51b6..01f71b0c6ec 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java @@ -18,6 +18,7 @@ package android.server.wm; import static android.server.wm.UiDeviceUtils.pressUnlockButton; import static android.server.wm.UiDeviceUtils.pressWakeupButton; +import static android.server.wm.WindowManagerState.STATE_RESUMED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; @@ -35,6 +36,7 @@ import static org.junit.Assert.assertNull; import android.app.Activity; import android.app.Instrumentation; import android.app.KeyguardManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Color; @@ -42,6 +44,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.PowerManager; +import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.service.displayhash.DisplayHashParams; import android.util.Size; @@ -78,6 +81,8 @@ import java.util.concurrent.TimeUnit; @Presubmit public class DisplayHashManagerTest { private static final int WAIT_TIME_S = 5; + private static final int TIMEOUT_MS = 1000; + private static final int SLEEP_TIMEOUT_MS = 200; private final Point mCenter = new Point(); private final Point mTestViewSize = new Point(200, 300); @@ -416,7 +421,9 @@ public class DisplayHashManagerTest { committedCallbackLatch.await(WAIT_TIME_S, TimeUnit.SECONDS); } catch (InterruptedException e) { } - waitForAllActivitiesResumed(); + ComponentName componentName = ComponentName.unflattenFromString( + "android.server.wm/android.server.wm.DisplayHashManagerTest$TestActivity"); + waitForActivityResumed(TIMEOUT_MS, componentName); byte[] expectedImageHash = new byte[]{-1, -1, 127, -1, -1, -1, 127, 127}; @@ -430,6 +437,20 @@ public class DisplayHashManagerTest { assertArrayEquals(expectedImageHash, verifiedDisplayHash.getImageHash()); } + private void waitForActivityResumed(int timeoutMs, ComponentName componentName) { + long endTime = System.currentTimeMillis() + timeoutMs; + while (endTime > System.currentTimeMillis()) { + mWmState.computeState(); + if (mWmState.hasActivityState(componentName, STATE_RESUMED)) { + SystemClock.sleep(SLEEP_TIMEOUT_MS); + mWmState.computeState(); + break; + } + SystemClock.sleep(SLEEP_TIMEOUT_MS); + mWmState.computeState(); + } + } + @Test public void testDisplayHashParams() { int width = 10; diff --git a/tests/signature/api-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml index f5d4db2e46a..d08de888bff 100644 --- a/tests/signature/api-check/system-annotation/AndroidTest.xml +++ b/tests/signature/api-check/system-annotation/AndroidTest.xml @@ -38,6 +38,7 @@ <option name="instrumentation-arg" key="expected-api-files" value="system-current.api.gz,system-removed.api.gz,car-system-current.api.gz,car-system-removed.api.gz" /> <option name="instrumentation-arg" key="annotation-for-exact-match" value="@android.annotation.SystemApi\(client=PRIVILEGED_APPS\)" /> <option name="runtime-hint" value="30s" /> + <option name="test-timeout" value="500000" /> <!-- Disable hidden API checks (http://b/171459260). --> <option name="hidden-api-checks" value="false" /> <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. --> diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java index d3db6dcdf43..292091bd8c1 100644 --- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java +++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java @@ -1090,6 +1090,7 @@ public final class CarPropertyManagerTest extends AbstractCarTestCase { getInfoVinVerifier(), getInfoMakeVerifier(), getInfoModelVerifier(), + getInfoModelYearVerifier(), getInfoFuelCapacityVerifier(), getInfoFuelTypeVerifier(), getInfoEvBatteryCapacityVerifier(), @@ -1498,8 +1499,8 @@ public final class CarPropertyManagerTest extends AbstractCarTestCase { Integer.class, mCarPropertyManager) .setAllPossibleEnumValues(possibleEnumValues) .setDependentOnProperty(VehiclePropertyIds.HANDS_ON_DETECTION_ENABLED, - ImmutableSet.of(Car.PERMISSION_READ_ADAS_SETTINGS, - Car.PERMISSION_CONTROL_ADAS_SETTINGS)) + ImmutableSet.of(Car.PERMISSION_READ_DRIVER_MONITORING_SETTINGS, + Car.PERMISSION_CONTROL_DRIVER_MONITORING_SETTINGS)) .verifyErrorStates() .addReadPermission(Car.PERMISSION_READ_DRIVER_MONITORING_STATES) .build(); @@ -1529,8 +1530,8 @@ public final class CarPropertyManagerTest extends AbstractCarTestCase { Integer.class, mCarPropertyManager) .setAllPossibleEnumValues(possibleEnumValues) .setDependentOnProperty(VehiclePropertyIds.HANDS_ON_DETECTION_ENABLED, - ImmutableSet.of(Car.PERMISSION_READ_ADAS_SETTINGS, - Car.PERMISSION_CONTROL_ADAS_SETTINGS)) + ImmutableSet.of(Car.PERMISSION_READ_DRIVER_MONITORING_SETTINGS, + Car.PERMISSION_CONTROL_DRIVER_MONITORING_SETTINGS)) .verifyErrorStates() .addReadPermission(Car.PERMISSION_READ_DRIVER_MONITORING_STATES) .build(); @@ -1708,10 +1709,26 @@ public final class CarPropertyManagerTest extends AbstractCarTestCase { } @Test - public void testInfoModelYearIfSupported() { + public void testInfoModelIfSupported() { getInfoModelVerifier().verify(); } + private VehiclePropertyVerifier<Integer> getInfoModelYearVerifier() { + return VehiclePropertyVerifier.newBuilder( + VehiclePropertyIds.INFO_MODEL_YEAR, + CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, + VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, + CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC, + Integer.class, mCarPropertyManager) + .addReadPermission(Car.PERMISSION_CAR_INFO) + .build(); + } + + @Test + public void testInfoModelYearIfSupported() { + getInfoModelYearVerifier().verify(); + } + private VehiclePropertyVerifier<Float> getInfoFuelCapacityVerifier() { return VehiclePropertyVerifier.newBuilder( VehiclePropertyIds.INFO_FUEL_CAPACITY, diff --git a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java index 20a1c69ecd8..5bea216ef0c 100644 --- a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java +++ b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java @@ -1678,25 +1678,25 @@ public class VehiclePropertyVerifier<T> { verifyHvacTemperatureIsValid(suggestedTempInFahrenheit, minTempInFahrenheitTimesTen, maxTempInFahrenheitTimesTen, incrementInFahrenheitTimesTen); - int suggestedTempInCelsiusTimesTen = suggestedTempInCelsius.intValue() * 10; - int suggestedTempInFahrenheitTimesTen = suggestedTempInFahrenheit.intValue() * 10; + int suggestedTempInCelsiusTimesTen = (int) (suggestedTempInCelsius * 10f); + int suggestedTempInFahrenheitTimesTen = (int) (suggestedTempInFahrenheit * 10f); int numIncrementsCelsius = - (suggestedTempInCelsiusTimesTen - minTempInCelsiusTimesTen) - / incrementInCelsiusTimesTen; + Math.round((suggestedTempInCelsiusTimesTen - minTempInCelsiusTimesTen) + / incrementInCelsiusTimesTen.floatValue()); int numIncrementsFahrenheit = - (suggestedTempInFahrenheitTimesTen - minTempInFahrenheitTimesTen) - / incrementInFahrenheitTimesTen; + Math.round((suggestedTempInFahrenheitTimesTen - minTempInFahrenheitTimesTen) + / incrementInFahrenheitTimesTen.floatValue()); assertWithMessage( - "The temperature in Celsius must be equivalent to the temperature in" - + " Fahrenheit.") + "The temperature in celsius must map to the same temperature in fahrenheit" + + " using the HVAC_TEMPERATURE_SET config array: " + + hvacTemperatureSetConfigArray) .that(numIncrementsFahrenheit) .isEqualTo(numIncrementsCelsius); } public static void verifyHvacTemperatureIsValid(float temp, int minTempTimesTen, int maxTempTimesTen, int incrementTimesTen) { - Float tempMultiplied = temp * 10.0f; - int intTempTimesTen = tempMultiplied.intValue(); + int intTempTimesTen = (int) (temp * 10f); assertWithMessage( "The temperature value " + intTempTimesTen + " must be at least " + minTempTimesTen + " and at most " + maxTempTimesTen) diff --git a/tests/tests/media/common/src/android/media/cts/MediaProjectionActivity.java b/tests/tests/media/common/src/android/media/cts/MediaProjectionActivity.java index 2223bc0ca54..b78e4ae7c95 100644 --- a/tests/tests/media/common/src/android/media/cts/MediaProjectionActivity.java +++ b/tests/tests/media/common/src/android/media/cts/MediaProjectionActivity.java @@ -22,10 +22,13 @@ import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.os.Bundle; import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -49,6 +52,11 @@ public class MediaProjectionActivity extends Activity { private static final int PERMISSION_CODE = 1; private static final int PERMISSION_DIALOG_WAIT_MS = 1000; private static final String ACCEPT_RESOURCE_ID = "android:id/button1"; + private static final String SYSTEM_UI_PACKAGE = "com.android.systemui"; + private static final String SPINNER_RESOURCE_ID = + SYSTEM_UI_PACKAGE + ":id/screen_share_mode_spinner"; + private static final String ENTIRE_SCREEN_STRING_RES_NAME = + "screen_share_permission_dialog_option_entire_screen"; private MediaProjectionManager mProjectionManager; private MediaProjection mMediaProjection; @@ -137,34 +145,81 @@ public class MediaProjectionActivity extends Activity { /** The permission dialog will be auto-opened by the activity - find it and accept */ public void dismissPermissionDialog() { // Ensure the device is initialized before interacting with any UI elements. - final UiDevice uiDevice = UiDevice.getInstance( - InstrumentationRegistry.getInstrumentation()); - - // Scroll down the dialog; on a device with a small screen the buttons may be below the - // warning text. + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); final boolean isWatch = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); - if (isWatch) { - final UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true)); - try { - if (!scrollable.scrollIntoView(new UiSelector().resourceId(ACCEPT_RESOURCE_ID))) { - Log.e(TAG, "Didn't find the accept button when scrolling"); - return; - } - Log.d(TAG, "This is a watch; we finished scrolling down to the buttons"); - } catch (UiObjectNotFoundException e) { - Log.d(TAG, "This is a watch, but there was no scrolling (the UI may not be " - + "scrollable"); + if (!isWatch) { + // if not testing on a watch device, then we need to select the entire screen option + // before pressing "Start recording" button. + if (!selectEntireScreenOption()) { + Log.e(TAG, "Couldn't select entire screen option"); } } + pressStartRecording(isWatch); + } + + private boolean selectEntireScreenOption() { + UiObject2 spinner = waitForObject(By.res(SPINNER_RESOURCE_ID)); + if (spinner == null) { + Log.e(TAG, "Couldn't find spinner to select projection mode"); + return false; + } + spinner.click(); - UiObject2 acceptButton = uiDevice.wait(Until.findObject(By.res(ACCEPT_RESOURCE_ID)), - PERMISSION_DIALOG_WAIT_MS); - if (acceptButton != null) { + UiObject2 entireScreenOption = waitForObject(By.text(getEntireScreenString())); + if (entireScreenOption == null) { + Log.e(TAG, "Couldn't find entire screen option"); + return false; + } + entireScreenOption.click(); + return true; + } + + private String getEntireScreenString() { + Resources sysUiResources; + try { + sysUiResources = getPackageManager().getResourcesForApplication(SYSTEM_UI_PACKAGE); + } catch (NameNotFoundException e) { + return null; + } + int resourceId = + sysUiResources.getIdentifier( + ENTIRE_SCREEN_STRING_RES_NAME, /* defType= */ "string", SYSTEM_UI_PACKAGE); + return sysUiResources.getString(resourceId); + } + + private void pressStartRecording(boolean isWatch) { + if (isWatch) { + scrollToStartRecordingButton(); + } + UiObject2 startRecordingButton = waitForObject(By.res(ACCEPT_RESOURCE_ID)); + if (startRecordingButton == null) { + Log.e(TAG, "Couldn't find start recording button"); + } else { Log.d(TAG, "found permission dialog after searching all windows, clicked"); - acceptButton.click(); + startRecordingButton.click(); } } + /** When testing on a small screen device, scrolls to a Start Recording button. */ + private void scrollToStartRecordingButton() { + // Scroll down the dialog; on a device with a small screen the elements may not be visible. + final UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true)); + try { + if (!scrollable.scrollIntoView(new UiSelector().resourceId(ACCEPT_RESOURCE_ID))) { + Log.e(TAG, "Didn't find " + ACCEPT_RESOURCE_ID + " when scrolling"); + return; + } + Log.d(TAG, "This is a watch; we finished scrolling down to the ui elements"); + } catch (UiObjectNotFoundException e) { + Log.d(TAG, "This is a watch, but there was no scrolling (UI may not be scrollable"); + } + } + + private UiObject2 waitForObject(BySelector selector) { + UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + return uiDevice.wait(Until.findObject(selector), PERMISSION_DIALOG_WAIT_MS); + } + @Override protected void onResume() { Log.i(TAG, "onResume"); diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java index f2fc35b3e5a..ac0c24ef0c2 100644 --- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java +++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java @@ -74,7 +74,8 @@ import java.util.function.Supplier; @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public class DecodeOnlyTest extends MediaTestBase { public static final boolean WAS_LAUNCHED_ON_U_OR_LATER = - SystemProperties.getInt("ro.board.first_api_level", Build.VERSION_CODES.CUR_DEVELOPMENT) + SystemProperties.getInt("ro.product.first_api_level", + Build.VERSION_CODES.CUR_DEVELOPMENT) >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE; private static final String MEDIA_DIR_STRING = WorkDir.getMediaDirString(); @@ -108,7 +109,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOnAvc() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledPerfectSeek(AVC_VIDEO, true); } @@ -117,7 +118,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOnVp9() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledPerfectSeek(VP9_VIDEO, true); } @@ -126,7 +127,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOnHevc() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledPerfectSeek(HEVC_VIDEO, true); } @@ -135,7 +136,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOffAvc() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledPerfectSeek(AVC_VIDEO, false); } @@ -144,7 +145,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOffVp9() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledPerfectSeek(VP9_VIDEO, false); } @@ -153,7 +154,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOffHevc() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledPerfectSeek(HEVC_VIDEO, false); } @@ -165,7 +166,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledTrickPlayHevc() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledTrickPlay(HEVC_VIDEO); } @@ -174,7 +175,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledTrickPlayAvc() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledTrickPlay(AVC_VIDEO); } @@ -183,7 +184,7 @@ public class DecodeOnlyTest extends MediaTestBase { @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledTrickPlayVp9() throws Exception { // Tunnel mode requires vendor support of the DECODE_ONLY feature - Assume.assumeTrue("First board API level is not Android 14 or later.", + Assume.assumeTrue("First API level is not Android 14 or later.", WAS_LAUNCHED_ON_U_OR_LATER); testTunneledTrickPlay(VP9_VIDEO); } diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java index 4721f8bc829..cb88f684207 100644 --- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java +++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java @@ -110,7 +110,8 @@ public class DecoderTest extends MediaTestBase { private static final String REPORT_LOG_NAME = "CtsMediaDecoderTestCases"; public static final boolean WAS_LAUNCHED_ON_S_OR_LATER = - SystemProperties.getInt("ro.board.first_api_level", Build.VERSION_CODES.CUR_DEVELOPMENT) + SystemProperties.getInt("ro.product.first_api_level", + Build.VERSION_CODES.CUR_DEVELOPMENT) >= Build.VERSION_CODES.S; private static boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R); @@ -3531,7 +3532,7 @@ public class DecoderTest extends MediaTestBase { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOnHevc() throws Exception { // Requires vendor support of the TUNNEL_PEEK feature - Assume.assumeTrue("First board API level is not Android 12 or later.", + Assume.assumeTrue("First API level is not Android 12 or later.", WAS_LAUNCHED_ON_S_OR_LATER); testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC, "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv", 25); @@ -3545,7 +3546,7 @@ public class DecoderTest extends MediaTestBase { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOnAvc() throws Exception { // Requires vendor support of the TUNNEL_PEEK feature - Assume.assumeTrue("First board API level is not Android 12 or later.", + Assume.assumeTrue("First API level is not Android 12 or later.", WAS_LAUNCHED_ON_S_OR_LATER); testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC, "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4", 25); @@ -3559,7 +3560,7 @@ public class DecoderTest extends MediaTestBase { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOnVp9() throws Exception { // Requires vendor support of the TUNNEL_PEEK feature - Assume.assumeTrue("First board API level is not Android 12 or later.", + Assume.assumeTrue("First API level is not Android 12 or later.", WAS_LAUNCHED_ON_S_OR_LATER); testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm", @@ -3632,7 +3633,7 @@ public class DecoderTest extends MediaTestBase { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOffHevc() throws Exception { // Requires vendor support of the TUNNEL_PEEK feature - Assume.assumeTrue("First board API level is not Android 12 or later.", + Assume.assumeTrue("First API level is not Android 12 or later.", WAS_LAUNCHED_ON_S_OR_LATER); testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_HEVC, "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv", 25); @@ -3646,7 +3647,7 @@ public class DecoderTest extends MediaTestBase { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOffAvc() throws Exception { // Requires vendor support of the TUNNEL_PEEK feature - Assume.assumeTrue("First board API level is not Android 12 or later.", + Assume.assumeTrue("First API level is not Android 12 or later.", WAS_LAUNCHED_ON_S_OR_LATER); testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_AVC, "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4", 25); @@ -3660,7 +3661,7 @@ public class DecoderTest extends MediaTestBase { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOffVp9() throws Exception { // Requires vendor support of the TUNNEL_PEEK feature - Assume.assumeTrue("First board API level is not Android 12 or later.", + Assume.assumeTrue("First API level is not Android 12 or later.", WAS_LAUNCHED_ON_S_OR_LATER); testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm", diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt index 8a65ad3accb..e19ad7a5eda 100644 --- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt +++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt @@ -158,7 +158,6 @@ class IntentTest : PackageInstallerTestBase() { clickInstallerUIButton(INSTALL_BUTTON_ID) // Install should not have succeeded - assertEquals(RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS)) assertNotInstalled() } finally { setSecureFrp(false) diff --git a/tests/tests/permissionpolicy/res/raw/android_manifest.xml b/tests/tests/permissionpolicy/res/raw/android_manifest.xml index fa6033ec367..83c658bce7a 100644 --- a/tests/tests/permissionpolicy/res/raw/android_manifest.xml +++ b/tests/tests/permissionpolicy/res/raw/android_manifest.xml @@ -5960,7 +5960,7 @@ <!-- @hide @SystemApi Allows an application to observe usage time of apps. The app can register for callbacks when apps reach a certain usage time limit, etc. --> <permission android:name="android.permission.OBSERVE_APP_USAGE" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature|privileged|role" /> <!-- @hide @TestApi @SystemApi Allows an application to change the app idle state of an app. <p>Not for use by third-party applications. --> @@ -6591,7 +6591,7 @@ it will be ignored. @hide --> <permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature|privileged|role" /> <!-- @SystemApi Allows entering or exiting car mode using a specified priority. This permission is required to use UiModeManager while specifying a priority for the calling diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp index 3aa25a56a0e..1bca40ac1bf 100644 --- a/tests/tests/security/Android.bp +++ b/tests/tests/security/Android.bp @@ -92,7 +92,6 @@ android_test { ":CtsPermissionBackupAppCert34", ":CtsPermissionBackupAppCert123", ":CtsPermissionBackupAppCert4History124", - ":TileServiceNullBindingTestApp", ], } diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml index aa29d2bdc95..fc858384128 100644 --- a/tests/tests/security/AndroidTest.xml +++ b/tests/tests/security/AndroidTest.xml @@ -63,7 +63,6 @@ <option name="push" value="CtsPermissionBackupAppCert123.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert123.apk" /> <option name="push" value="CtsPermissionBackupAppCert34.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert34.apk" /> <option name="push" value="CtsPermissionBackupAppCert4History124.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4History124.apk" /> - <option name="push" value="TileServiceNullBindingTestApp.apk->/data/local/tmp/cts/security/TileServiceNullBindingTestApp.apk" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/tests/tests/security/TileServiceNullBindingTestApp/Android.bp b/tests/tests/security/TileServiceNullBindingTestApp/Android.bp deleted file mode 100644 index 149550890a4..00000000000 --- a/tests/tests/security/TileServiceNullBindingTestApp/Android.bp +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (C) 2020 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT 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 { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -android_test_helper_app { - name: "TileServiceNullBindingTestApp", - srcs: [ - "src/**/*.kt", - ], - static_libs: [ - "kotlin-stdlib", - ], - - min_sdk_version: "30", - target_sdk_version: "33", -} diff --git a/tests/tests/security/TileServiceNullBindingTestApp/AndroidManifest.xml b/tests/tests/security/TileServiceNullBindingTestApp/AndroidManifest.xml deleted file mode 100644 index c7193769bdc..00000000000 --- a/tests/tests/security/TileServiceNullBindingTestApp/AndroidManifest.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?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. - --> - -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="android.security.cts.tileservice"> - - - <application android:label="TileService Null Binding Test App" - android:icon="@android:drawable/ic_info"> - <activity android:name=".BackgroundLaunchActivity" - android:exported="false"> - </activity> - <activity android:name=".ActivityStarterActivity" - android:exported="true"> - </activity> - <service android:name=".NullBindingTileService" - android:label="Tile Service" - android:exported="true" - android:icon="@android:drawable/ic_info" - android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> - <intent-filter> - <action android:name="android.service.quicksettings.action.QS_TILE" /> - </intent-filter> - </service> - </application> -</manifest> diff --git a/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/ActivityStarterActivity.kt b/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/ActivityStarterActivity.kt deleted file mode 100644 index 3d73c04ca82..00000000000 --- a/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/ActivityStarterActivity.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.security.cts.tileservice - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import android.os.Handler -import android.widget.FrameLayout - -class ActivityStarterActivity : Activity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(FrameLayout(this)) - } - - override fun onResume() { - super.onResume() - Handler().postDelayed({ - startActivity(Intent(applicationContext, BackgroundLaunchActivity::class.java)) - }, DELAY) - minimizeApp() - } - - private fun minimizeApp() { - val startMain = Intent(Intent.ACTION_MAIN) - startMain.addCategory(Intent.CATEGORY_HOME) - startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - startActivity(startMain) - } - - companion object { - private const val DELAY = 15000L - } -} diff --git a/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/BackgroundLaunchActivity.kt b/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/BackgroundLaunchActivity.kt deleted file mode 100644 index 43244eedbcb..00000000000 --- a/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/BackgroundLaunchActivity.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.security.cts.tileservice - -import android.app.Activity -import android.content.Intent -import android.os.Bundle - -class BackgroundLaunchActivity : Activity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - sendBroadcast(Intent(BACKGROUND_ACTIVITY_STARTED)) - finish() - } - - companion object { - private const val BACKGROUND_ACTIVITY_STARTED = - "android.security.cts.tileservice.BACKGROUND_ACTIVITY_STARTED" - } -} diff --git a/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/NullBindingTileService.kt b/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/NullBindingTileService.kt deleted file mode 100644 index 7ff03826df3..00000000000 --- a/tests/tests/security/TileServiceNullBindingTestApp/src/android/security/cts/tileservice/NullBindingTileService.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.security.cts.tileservice - -import android.content.Intent -import android.os.IBinder -import android.service.quicksettings.TileService - -class NullBindingTileService : TileService() { - override fun onBind(intent: Intent?): IBinder? { - return null.also { - sendBroadcast(Intent(ON_NULL_BINDING)) - } - } - - companion object { - private const val ON_NULL_BINDING = "android.security.cts.tileservice.ON_NULL_BINDING" - } -} diff --git a/tests/tests/security/src/android/security/cts/Bug_300903792.kt b/tests/tests/security/src/android/security/cts/Bug_300903792.kt deleted file mode 100644 index 5b2784b93e7..00000000000 --- a/tests/tests/security/src/android/security/cts/Bug_300903792.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.security.cts - -import android.content.ComponentName -import android.content.Intent -import android.platform.test.annotations.AsbSecurityTest -import android.service.quicksettings.TileService -import android.util.Log -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation -import com.android.compatibility.common.util.BlockingBroadcastReceiver -import com.android.compatibility.common.util.SystemUtil -import com.android.sts.common.util.StsExtraBusinessLogicTestCase -import org.junit.After -import org.junit.Assert.fail -import org.junit.Assume.assumeTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class Bug_300903792 : StsExtraBusinessLogicTestCase() { - - @Before - fun setUp() { - assumeTrue(TileService.isQuickSettingsSupported()) - installPackage(TILE_SERVICE_APP_LOCATION) - } - - @After - fun tearDown() { - SystemUtil.runShellCommand(REMOVE_TILE_COMMAND) - Log.d("TestRunner", "Uninstalling $TILE_SERVICE_PACKAGE") - uninstallPackage(TILE_SERVICE_PACKAGE) - } - - @Test - @AsbSecurityTest(cveBugId = [300903792]) - fun testPocBug_300903792() { - val context = getInstrumentation().context - val nullBindingReceiver = BlockingBroadcastReceiver(context, ON_NULL_BINDING) - // First we add the tile, we should receive a broadcast once it has bound. - // We expect that the tile will be bound to notify `onTileAdded` and onNullBinding will - // happen. - try { - nullBindingReceiver.register() - SystemUtil.runShellCommand(ADD_TILE_COMMAND) - nullBindingReceiver.awaitForBroadcast(ONE_MINUTE_IN_MILLIS) - } finally { - nullBindingReceiver.unregisterQuietly() - } - - val backgroundActivityStarted = - BlockingBroadcastReceiver(context, BACKGROUND_ACTIVITY_STARTED) - // We start an activity that will schedule another activity to start and then go home - // (putting itself in the background). We expect that the backgroundActivity is not started, - // but if the security issue is not patched, it will. - try { - backgroundActivityStarted.register() - context.startActivity( - Intent() - .setComponent(ACTIVITY_STARTER_COMPONENT) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - ) - val intent = backgroundActivityStarted.awaitForBroadcast(ONE_MINUTE_IN_MILLIS) - if (intent != null) { - fail("Vulnerable to b/300903792! Activity started from the background") - } - } finally { - backgroundActivityStarted.unregisterQuietly() - } - } - - private fun installPackage(apkPath: String) { - val result = SystemUtil.runShellCommand("pm install -r $apkPath") - Log.d("security", "Install result: $result") - } - - private fun uninstallPackage(packageName: String) { - SystemUtil.runShellCommand("pm uninstall $packageName") - } - - companion object { - private const val TILE_SERVICE_APP_LOCATION = - "/data/local/tmp/cts/security/TileServiceNullBindingTestApp.apk" - private const val TILE_SERVICE_PACKAGE = "android.security.cts.tileservice" - private const val TILE_SERVICE_NAME = ".NullBindingTileService" - private const val ACTIVITY_STARTER_NAME = ".ActivityStarterActivity" - - private val TILE_SERVICE_COMPONENT = - ComponentName.createRelative(TILE_SERVICE_PACKAGE, TILE_SERVICE_NAME) - private val ACTIVITY_STARTER_COMPONENT = - ComponentName.createRelative(TILE_SERVICE_PACKAGE, ACTIVITY_STARTER_NAME) - - private const val BACKGROUND_ACTIVITY_STARTED = - "android.security.cts.tileservice.BACKGROUND_ACTIVITY_STARTED" - - private const val ON_NULL_BINDING = "android.security.cts.tileservice.ON_NULL_BINDING" - - private val ADD_TILE_COMMAND = - "cmd statusbar add-tile ${TILE_SERVICE_COMPONENT.flattenToString()}" - private val REMOVE_TILE_COMMAND = - "cmd statusbar remove-tile ${TILE_SERVICE_COMPONENT.flattenToString()}" - - private const val ONE_MINUTE_IN_MILLIS = 60 * 1000L - } -} diff --git a/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java index 74fdf642e09..a23a8904b4f 100644 --- a/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java +++ b/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java @@ -680,8 +680,8 @@ public class SingleDeviceTest extends WifiJUnit3TestBase { Characteristics characteristics = mWifiAwareManager.getCharacteristics(); assertNotNull("Wi-Fi Aware characteristics are null", characteristics); assertEquals("Service Name Length", characteristics.getMaxServiceNameLength(), 255); - assertEquals("Service Specific Information Length", - characteristics.getMaxServiceSpecificInfoLength(), 255); + assertTrue("Service Specific Information Length", + characteristics.getMaxServiceSpecificInfoLength() >= 255); assertEquals("Match Filter Length", characteristics.getMaxMatchFilterLength(), 255); assertNotEquals("Cipher suites", characteristics.getSupportedCipherSuites(), 0); assertTrue("Max number of NDP", characteristics.getNumberOfSupportedDataPaths() > 0); diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed index 47fcea8c89d..4b477d08e2c 100755 --- a/tools/cts-tradefed/etc/cts-tradefed +++ b/tools/cts-tradefed/etc/cts-tradefed @@ -36,7 +36,7 @@ realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" } -checkPath aapt +checkPath aapt2 checkPath adb checkPath java |