Merge "AGP 8.3.0-alpha10 and corresponding Studio" into androidx-main
diff --git a/activity/activity/api/api_lint.ignore b/activity/activity/api/api_lint.ignore
index cc91968..c271630 100644
--- a/activity/activity/api/api_lint.ignore
+++ b/activity/activity/api/api_lint.ignore
@@ -55,11 +55,6 @@
androidx.activity.result.IntentSenderRequest does not declare a `getFlags()` method matching method androidx.activity.result.IntentSenderRequest.Builder.setFlags(int,int)
-RegistrationName: androidx.activity.OnBackPressedDispatcher#addCallback(androidx.activity.OnBackPressedCallback):
- Callback methods should be named register/unregister; was addCallback
-RegistrationName: androidx.activity.OnBackPressedDispatcher#addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback):
- Callback methods should be named register/unregister; was addCallback
-
PairedRegistration: androidx.activity.OnBackPressedDispatcher#addCallback(androidx.activity.OnBackPressedCallback):
Found addCallback but not removeCallback in androidx.activity.OnBackPressedDispatcher
PairedRegistration: androidx.activity.OnBackPressedDispatcher#addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback):
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/ObserverManager.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/ObserverManager.java
index bf6306b..d7c46ef 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/ObserverManager.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/ObserverManager.java
@@ -390,14 +390,13 @@
Map<String, Set<String>> schemaChanges = observerInfo.mSchemaChanges;
Map<DocumentChangeGroupKey, Set<String>> documentChanges = observerInfo.mDocumentChanges;
if (schemaChanges.isEmpty() && documentChanges.isEmpty()) {
+ // There is nothing to send, return early.
return;
}
- if (!schemaChanges.isEmpty()) {
- observerInfo.mSchemaChanges = new ArrayMap<>();
- }
- if (!documentChanges.isEmpty()) {
- observerInfo.mDocumentChanges = new ArrayMap<>();
- }
+ // Clean the pending changes in the observer. We already copy pending changes to local
+ // variables.
+ observerInfo.mSchemaChanges = new ArrayMap<>();
+ observerInfo.mDocumentChanges = new ArrayMap<>();
// Dispatch the pending changes
observerInfo.mExecutor.execute(() -> {
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
index 2054bee..a6374da 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
@@ -850,32 +850,36 @@
new ObserverSpec.Builder().addFilterSchemas("TestAddObserver-Type").build(),
EXECUTOR,
observer);
+ 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()));
- // 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"))
- );
+ // 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
@@ -906,91 +910,98 @@
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();
- // 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();
- // 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()));
- 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);
- // 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"))
+ );
- 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"))
- );
+ // 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
@@ -1017,95 +1028,102 @@
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();
- // 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();
- // 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()));
- 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);
- // 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()));
- // 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);
- // 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"))
+ );
- 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"))
- );
+ // 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
@@ -1150,65 +1168,72 @@
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();
- // 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();
- // 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);
- // 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"))
+ );
- 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"))
- );
+ // 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
@@ -1236,33 +1261,37 @@
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()));
- 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"))
- );
+ // 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
@@ -1299,93 +1328,100 @@
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();
- // 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();
- // 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()));
- checkIsBatchResultSuccess(
- mDb1.putAsync(new PutDocumentsRequest.Builder()
- .addGenericDocuments(email1, gift1).build()));
+ // Make sure the notifications were received.
+ temporaryObserver.waitForNotificationCount(2);
+ permanentObserver.waitForNotificationCount(2);
- // 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);
- 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);
- // Unregister temporaryObserver
- mGlobalSearchSession.unregisterObserverCallback(
- mContext.getPackageName(), temporaryObserver);
+ // Index some more documents
+ checkIsBatchResultSuccess(
+ mDb1.putAsync(new PutDocumentsRequest.Builder()
+ .addGenericDocuments(email2, gift2).build()));
- // 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);
- // 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);
+ 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
@@ -1459,40 +1495,45 @@
new ObserverSpec.Builder().build(),
EXECUTOR,
observer);
+ 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();
- // 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();
- 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();
- // 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();
+ 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
@@ -1517,19 +1558,24 @@
EXECUTOR,
observer);
- // Remove Type2
- mDb1.setSchemaAsync(
- new SetSchemaRequest.Builder()
- .addSchemas(new AppSearchSchema.Builder("Type1").build())
- .setForceOverride(true)
- .build())
- .get();
+ 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();
+ 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
@@ -1561,45 +1607,48 @@
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")
+ 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();
+ .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")
+ // 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();
+ .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
@@ -1637,42 +1686,44 @@
new ObserverSpec.Builder().addFilterSchemas("Type2").build(),
EXECUTOR,
observer);
+ 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();
- // 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
public void testRegisterObserver_schemaMigration() throws Exception {
assumeTrue(mDb1.getFeatures().isFeatureSupported(
Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
-
// Add a schema with two types
mDb1.setSchemaAsync(new SetSchemaRequest.Builder()
.setVersion(1)
@@ -1720,120 +1771,127 @@
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;
- }
+ 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 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 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 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();
+ @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);
+ // 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();
+ // 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/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index b594507..57cddb5 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -143,9 +143,10 @@
project.tasks.withType(Zip::class.java).configureEach { it.configureForHermeticBuild() }
project.tasks.withType(Copy::class.java).configureEach { it.configureForHermeticBuild() }
+ val allHostTests = project.tasks.register("allHostTests").get()
// copy host side test results to DIST
project.tasks.withType(AbstractTestTask::class.java) { task ->
- configureTestTask(project, task)
+ configureTestTask(project, task, allHostTests)
}
project.tasks.withType(Test::class.java) { task -> configureJvmTestTask(project, task) }
@@ -241,7 +242,12 @@
}
}
- private fun configureTestTask(project: Project, task: AbstractTestTask) {
+ private fun configureTestTask(
+ project: Project,
+ task: AbstractTestTask,
+ anchorTask: Task,
+ ) {
+ anchorTask.dependsOn(task)
val ignoreFailuresProperty =
project.providers.gradleProperty(TEST_FAILURES_DO_NOT_FAIL_TEST_TASK)
val ignoreFailures = ignoreFailuresProperty.isPresent
diff --git a/busytown/androidx_host_tests.sh b/busytown/androidx_host_tests.sh
index 3555073..4c0b17b 100755
--- a/busytown/androidx_host_tests.sh
+++ b/busytown/androidx_host_tests.sh
@@ -5,7 +5,7 @@
cd "$(dirname $0)"
-impl/build.sh test zipOwnersFiles createModuleInfo \
+impl/build.sh test allHostTests zipOwnersFiles createModuleInfo \
-Pandroidx.ignoreTestFailures \
-Pandroidx.displayTestOutput=false \
"$@"
diff --git a/busytown/androidx_host_tests_max_dep_versions.sh b/busytown/androidx_host_tests_max_dep_versions.sh
index 5dbf2ee..c979e17 100755
--- a/busytown/androidx_host_tests_max_dep_versions.sh
+++ b/busytown/androidx_host_tests_max_dep_versions.sh
@@ -5,7 +5,7 @@
cd "$(dirname $0)"
-impl/build.sh test zipOwnersFiles createModuleInfo \
+impl/build.sh test allHostTests zipOwnersFiles createModuleInfo \
-Pandroidx.useMaxDepVersions \
-Pandroidx.displayTestOutput=false \
-Pandroidx.ignoreTestFailures "$@"
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 692218f..37809e9 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -974,8 +974,23 @@
property public final long trailingIconColor;
}
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ModalBottomSheetDefaults {
+ method public androidx.compose.material3.ModalBottomSheetProperties properties(optional androidx.compose.ui.window.SecureFlagPolicy securePolicy, optional boolean isFocusable, optional boolean shouldDismissOnBackPress);
+ field public static final androidx.compose.material3.ModalBottomSheetDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class ModalBottomSheetProperties {
+ ctor public ModalBottomSheetProperties(androidx.compose.ui.window.SecureFlagPolicy securePolicy, boolean isFocusable, boolean shouldDismissOnBackPress);
+ method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+ method public boolean getShouldDismissOnBackPress();
+ method public boolean isFocusable();
+ property public final boolean isFocusable;
+ property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+ property public final boolean shouldDismissOnBackPress;
+ }
+
public final class ModalBottomSheet_androidKt {
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.window.SecureFlagPolicy securePolicy, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.ModalBottomSheetProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
}
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 692218f..37809e9 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -974,8 +974,23 @@
property public final long trailingIconColor;
}
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ModalBottomSheetDefaults {
+ method public androidx.compose.material3.ModalBottomSheetProperties properties(optional androidx.compose.ui.window.SecureFlagPolicy securePolicy, optional boolean isFocusable, optional boolean shouldDismissOnBackPress);
+ field public static final androidx.compose.material3.ModalBottomSheetDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class ModalBottomSheetProperties {
+ ctor public ModalBottomSheetProperties(androidx.compose.ui.window.SecureFlagPolicy securePolicy, boolean isFocusable, boolean shouldDismissOnBackPress);
+ method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+ method public boolean getShouldDismissOnBackPress();
+ method public boolean isFocusable();
+ property public final boolean isFocusable;
+ property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+ property public final boolean shouldDismissOnBackPress;
+ }
+
public final class ModalBottomSheet_androidKt {
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.window.SecureFlagPolicy securePolicy, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.ModalBottomSheetProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
}
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
index 2c6213d..b130fd2 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
@@ -1336,7 +1336,8 @@
ModalBottomSheet(
sheetState = sheetState,
onDismissRequest = {},
- windowInsets = windowInsets
+ windowInsets = windowInsets,
+ properties = ModalBottomSheetDefaults.properties(isFocusable = true)
) {
Box(Modifier.testTag(sheetTag)) {
TextField(
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
index 10c74d8..6ff1fcfc 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
@@ -48,6 +48,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
@@ -124,8 +125,8 @@
* @param dragHandle Optional visual marker to swipe the bottom sheet.
* @param windowInsets window insets to be passed to the bottom sheet window via [PaddingValues]
* params.
- * @param securePolicy Policy for setting [WindowManager.LayoutParams.FLAG_SECURE] on the bottom
- * sheet's window.
+ * @param properties [ModalBottomSheetProperties] for further customization of this
+ * modal bottom sheet's behavior.
* @param content The content to be displayed inside the bottom sheet.
*/
@Composable
@@ -142,7 +143,7 @@
scrimColor: Color = BottomSheetDefaults.ScrimColor,
dragHandle: @Composable (() -> Unit)? = { BottomSheetDefaults.DragHandle() },
windowInsets: WindowInsets = BottomSheetDefaults.windowInsets,
- securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,
+ properties: ModalBottomSheetProperties = ModalBottomSheetDefaults.properties(),
content: @Composable ColumnScope.() -> Unit,
) {
// b/291735717 Remove this once deprecated methods without density are removed
@@ -167,7 +168,7 @@
}
ModalBottomSheetPopup(
- securePolicy = securePolicy,
+ properties = properties,
onDismissRequest = {
if (sheetState.currentValue == Expanded && sheetState.hasPartiallyExpandedState) {
scope.launch { sheetState.partialExpand() }
@@ -281,6 +282,70 @@
}
/**
+ * Properties used to customize the behavior of a [ModalBottomSheet].
+ *
+ * @param securePolicy Policy for setting [WindowManager.LayoutParams.FLAG_SECURE] on the bottom
+ * sheet's window.
+ * @param isFocusable Whether the modal bottom sheet is focusable. When true,
+ * the modal bottom sheet will receive IME events and key presses, such as when
+ * the back button is pressed.
+ * @param shouldDismissOnBackPress Whether the modal bottom sheet can be dismissed by pressing
+ * the back button. If true, pressing the back button will call onDismissRequest.
+ * Note that [isFocusable] must be set to true in order to receive key events such as
+ * the back button - if the modal bottom sheet is not focusable then this property does nothing.
+ */
+@ExperimentalMaterial3Api
+class ModalBottomSheetProperties(
+ val securePolicy: SecureFlagPolicy,
+ val isFocusable: Boolean,
+ val shouldDismissOnBackPress: Boolean
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is ModalBottomSheetProperties) return false
+
+ if (securePolicy != other.securePolicy) return false
+ if (isFocusable != other.isFocusable) return false
+ if (shouldDismissOnBackPress != other.shouldDismissOnBackPress) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = securePolicy.hashCode()
+ result = 31 * result + isFocusable.hashCode()
+ result = 31 * result + shouldDismissOnBackPress.hashCode()
+ return result
+ }
+}
+
+/**
+ * Default values for [ModalBottomSheet]
+ */
+@Immutable
+@ExperimentalMaterial3Api
+object ModalBottomSheetDefaults {
+ /**
+ * Properties used to customize the behavior of a [ModalBottomSheet].
+ *
+ * @param securePolicy Policy for setting [WindowManager.LayoutParams.FLAG_SECURE] on the bottom
+ * sheet's window.
+ * @param isFocusable Whether the modal bottom sheet is focusable. When true,
+ * the modal bottom sheet will receive IME events and key presses, such as when
+ * the back button is pressed.
+ * @param shouldDismissOnBackPress Whether the modal bottom sheet can be dismissed by pressing
+ * the back button. If true, pressing the back button will call onDismissRequest.
+ * Note that [isFocusable] must be set to true in order to receive key events such as
+ * the back button - if the modal bottom sheet is not focusable then this property does nothing.
+ */
+ fun properties(
+ securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,
+ isFocusable: Boolean = true,
+ shouldDismissOnBackPress: Boolean = true
+ ) = ModalBottomSheetProperties(securePolicy, isFocusable, shouldDismissOnBackPress)
+}
+
+/**
* Create and [remember] a [SheetState] for [ModalBottomSheet].
*
* @param skipPartiallyExpanded Whether the partially expanded state, if the sheet is tall enough,
@@ -359,9 +424,10 @@
/**
* Popup specific for modal bottom sheet.
*/
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun ModalBottomSheetPopup(
- securePolicy: SecureFlagPolicy,
+ properties: ModalBottomSheetProperties,
onDismissRequest: () -> Unit,
windowInsets: WindowInsets,
content: @Composable () -> Unit,
@@ -374,7 +440,7 @@
val configuration = LocalConfiguration.current
val modalBottomSheetWindow = remember(configuration) {
ModalBottomSheetWindow(
- securePolicy = securePolicy,
+ properties = properties,
onDismissRequest = onDismissRequest,
composeView = view,
saveId = id
@@ -411,11 +477,12 @@
}
/** Custom compose view for [ModalBottomSheet] */
+@OptIn(ExperimentalMaterial3Api::class)
private class ModalBottomSheetWindow(
- private val securePolicy: SecureFlagPolicy,
+ private val properties: ModalBottomSheetProperties,
private var onDismissRequest: () -> Unit,
private val composeView: View,
- saveId: UUID,
+ saveId: UUID
) :
AbstractComposeView(composeView.context),
ViewTreeObserver.OnGlobalLayoutListener,
@@ -467,12 +534,19 @@
// Security flag
val secureFlagEnabled =
- securePolicy.shouldApplySecureFlag(composeView.isFlagSecureEnabled())
+ properties.securePolicy.shouldApplySecureFlag(composeView.isFlagSecureEnabled())
if (secureFlagEnabled) {
flags = flags or WindowManager.LayoutParams.FLAG_SECURE
} else {
flags = flags and (WindowManager.LayoutParams.FLAG_SECURE.inv())
}
+
+ // Focusable
+ if (!properties.isFocusable) {
+ flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ } else {
+ flags = flags and (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE.inv())
+ }
}
private var content: @Composable () -> Unit by mutableStateOf({})
@@ -509,7 +583,7 @@
* Taken from PopupWindow. Calls [onDismissRequest] when back button is pressed.
*/
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
- if (event.keyCode == KeyEvent.KEYCODE_BACK) {
+ if (event.keyCode == KeyEvent.KEYCODE_BACK && properties.shouldDismissOnBackPress) {
if (keyDispatcherState == null) {
return super.dispatchKeyEvent(event)
}
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopTextInputSessionTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopTextInputSessionTest.kt
index f0d005f..a9a9158 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopTextInputSessionTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopTextInputSessionTest.kt
@@ -31,6 +31,7 @@
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -39,6 +40,7 @@
@RunWith(JUnit4::class)
class DesktopTextInputSessionTest {
+ @Ignore // b/308619798
@Test
fun startInputMethod_setsAndClearsRequestsAndListeners() = runTest {
val inputComponent = TestInputComponent()
diff --git a/glance/glance-appwidget/api/current.txt b/glance/glance-appwidget/api/current.txt
index 23a57ea..f3d101b 100644
--- a/glance/glance-appwidget/api/current.txt
+++ b/glance/glance-appwidget/api/current.txt
@@ -12,7 +12,7 @@
public final class AppWidgetComposerKt {
method public static suspend Object? compose(androidx.glance.appwidget.GlanceAppWidget, android.content.Context context, optional androidx.glance.GlanceId id, optional android.os.Bundle? options, optional androidx.compose.ui.unit.DpSize? size, optional Object? state, kotlin.coroutines.Continuation<? super android.widget.RemoteViews>);
- method @SuppressCompatibility @androidx.glance.ExperimentalGlanceApi public static kotlinx.coroutines.flow.Flow<android.widget.RemoteViews> runComposition(androidx.glance.appwidget.GlanceAppWidget, android.content.Context context, optional androidx.glance.GlanceId id, optional android.os.Bundle options, optional java.util.List<androidx.compose.ui.unit.DpSize> sizes, optional Object? state);
+ method @SuppressCompatibility @androidx.glance.ExperimentalGlanceApi public static kotlinx.coroutines.flow.Flow<android.widget.RemoteViews> runComposition(androidx.glance.appwidget.GlanceAppWidget, android.content.Context context, optional androidx.glance.GlanceId id, optional android.os.Bundle options, optional java.util.List<androidx.compose.ui.unit.DpSize>? sizes, optional Object? state);
}
public final class BackgroundKt {
diff --git a/glance/glance-appwidget/api/restricted_current.txt b/glance/glance-appwidget/api/restricted_current.txt
index 23a57ea..f3d101b 100644
--- a/glance/glance-appwidget/api/restricted_current.txt
+++ b/glance/glance-appwidget/api/restricted_current.txt
@@ -12,7 +12,7 @@
public final class AppWidgetComposerKt {
method public static suspend Object? compose(androidx.glance.appwidget.GlanceAppWidget, android.content.Context context, optional androidx.glance.GlanceId id, optional android.os.Bundle? options, optional androidx.compose.ui.unit.DpSize? size, optional Object? state, kotlin.coroutines.Continuation<? super android.widget.RemoteViews>);
- method @SuppressCompatibility @androidx.glance.ExperimentalGlanceApi public static kotlinx.coroutines.flow.Flow<android.widget.RemoteViews> runComposition(androidx.glance.appwidget.GlanceAppWidget, android.content.Context context, optional androidx.glance.GlanceId id, optional android.os.Bundle options, optional java.util.List<androidx.compose.ui.unit.DpSize> sizes, optional Object? state);
+ method @SuppressCompatibility @androidx.glance.ExperimentalGlanceApi public static kotlinx.coroutines.flow.Flow<android.widget.RemoteViews> runComposition(androidx.glance.appwidget.GlanceAppWidget, android.content.Context context, optional androidx.glance.GlanceId id, optional android.os.Bundle options, optional java.util.List<androidx.compose.ui.unit.DpSize>? sizes, optional Object? state);
}
public final class BackgroundKt {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetComposer.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetComposer.kt
index 94a8428..c751aa0 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetComposer.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetComposer.kt
@@ -54,7 +54,7 @@
context = context,
id = id,
options = options ?: Bundle(),
- sizes = listOf(size ?: DpSize.Zero),
+ sizes = size?.let { listOf(size) },
state = state
).first()
@@ -70,24 +70,35 @@
* flow is running. This currently does not support resizing (you have to run the flow again with
* new [sizes]) or reloading the [androidx.glance.state.GlanceStateDefinition] state value.
*/
+@SuppressLint("PrimitiveInCollection")
@ExperimentalGlanceApi
fun GlanceAppWidget.runComposition(
@Suppress("ContextFirst") context: Context,
id: GlanceId = createFakeAppWidgetId(),
options: Bundle = Bundle(),
- @SuppressLint("PrimitiveInCollection") sizes: List<DpSize> = listOf(DpSize.Zero),
+ sizes: List<DpSize>? = null,
state: Any? = null,
): Flow<RemoteViews> = flow {
val session = AppWidgetSession(
widget = this@runComposition,
id = id as AppWidgetId,
- initialOptions = optionsBundleOf(sizes).apply { putAll(options) },
+ initialOptions = sizes?.let { optionsBundleOf(it).apply { putAll(options) } } ?: options,
initialGlanceState = state,
lambdaReceiver = ComponentName(context, UnmanagedSessionReceiver::class.java),
- // If not composing for a bound widget, override to SizeMode.Exact so we can use the sizes
- // provided to this function (by setting app widget options).
- sizeMode =
- if (id.isFakeId && sizeMode !is SizeMode.Responsive) SizeMode.Exact else sizeMode,
+ sizeMode = if (sizes != null) {
+ // If sizes are provided to this function, override to SizeMode.Exact so we can use them.
+ SizeMode.Exact
+ } else if (sizeMode is SizeMode.Responsive || id.isRealId) {
+ // If sizes are not provided and the widget is SizeMode.Responsive, use those sizes.
+ // Else if sizes are not provided but this is a bound widget, use the widget's sizeMode
+ // (Single or Exact).
+ sizeMode
+ } else {
+ // When no sizes are provided, the widget is not SizeMode.Responsive, and we are not
+ // composing for a bound widget, use SizeMode.Exact (which means AppWidgetSession will
+ // use DpSize.Zero).
+ SizeMode.Exact
+ },
shouldPublish = false,
)
coroutineScope {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt
index bc2e857..022de6d 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt
@@ -97,7 +97,7 @@
}
private var glanceState by mutableStateOf(initialGlanceState, neverEqualPolicy())
- private var options by mutableStateOf(initialOptions ?: Bundle.EMPTY, neverEqualPolicy())
+ private var options by mutableStateOf(initialOptions, neverEqualPolicy())
private var lambdas = mapOf<String, List<LambdaAction>>()
internal val lastRemoteViews = MutableStateFlow<RemoteViews?>(null)
@@ -108,7 +108,7 @@
CompositionLocalProvider(
LocalContext provides context,
LocalGlanceId provides id,
- LocalAppWidgetOptions provides options,
+ LocalAppWidgetOptions provides (options ?: Bundle.EMPTY),
LocalState provides glanceState,
) {
var minSize by remember { mutableStateOf(DpSize.Zero) }
@@ -123,12 +123,17 @@
manager,
id.appWidgetId
)
- options = manager.getAppWidgetOptions(id.appWidgetId)
+ if (options == null) {
+ options = manager.getAppWidgetOptions(id.appWidgetId)
+ }
}
- widget.stateDefinition?.let {
- glanceState =
- configManager.getValue(context, it, key)
- }
+ // Only get a Glance state value if we did not receive an initial value.
+ widget.stateDefinition
+ ?.takeIf { glanceState == null }
+ ?.let { stateDefinition ->
+ glanceState =
+ configManager.getValue(context, stateDefinition, key)
+ }
value = true
}
}
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index b314955..67db5c3 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -26,5 +26,5 @@
# Disable docs
androidx.enableDocumentation=false
androidx.playground.snapshotBuildId=10956675
-androidx.playground.metalavaBuildId=10969629
+androidx.playground.metalavaBuildId=11029641
androidx.studio.type=playground
\ No newline at end of file
diff --git a/room/room-runtime/api/api_lint.ignore b/room/room-runtime/api/api_lint.ignore
index 9c5918f..bb9e047 100644
--- a/room/room-runtime/api/api_lint.ignore
+++ b/room/room-runtime/api/api_lint.ignore
@@ -62,9 +62,6 @@
PairedRegistration: androidx.room.RoomDatabase.Builder#addCallback(androidx.room.RoomDatabase.Callback):
Found addCallback but not removeCallback in androidx.room.RoomDatabase.Builder
-RegistrationName: androidx.room.RoomDatabase.Builder#addCallback(androidx.room.RoomDatabase.Callback):
- Callback methods should be named register/unregister; was addCallback
-
StaticFinalBuilder: androidx.room.RoomDatabase.Builder:
Builder must be final: androidx.room.RoomDatabase.Builder