Skip to content

Commit 4b551b2

Browse files
authored
Merge branch 'master' into wuandy/FixSetterReturn
2 parents 0d4687b + bb0ac26 commit 4b551b2

File tree

19 files changed

+327
-134
lines changed

19 files changed

+327
-134
lines changed

buildSrc/build.gradle.kts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@ ktfmt {
4141
googleStyle()
4242
}
4343

44-
java {
45-
sourceCompatibility = JavaVersion.VERSION_1_8
46-
targetCompatibility = JavaVersion.VERSION_1_8
47-
}
48-
4944
dependencies {
5045
// Firebase performance plugin, it should be added here because of how gradle dependency
5146
// resolution works, otherwise it breaks Fireperf Test Apps.
@@ -70,8 +65,8 @@ dependencies {
7065

7166
implementation(libs.kotlinx.serialization.json)
7267
implementation("com.google.code.gson:gson:2.8.9")
73-
implementation("com.android.tools.build:gradle:7.3.1")
74-
implementation("com.android.tools.build:builder-test-api:7.2.2")
68+
implementation("com.android.tools.build:gradle:7.4.2")
69+
implementation("com.android.tools.build:builder-test-api:7.4.2")
7570
implementation("gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.9")
7671

7772
testImplementation(libs.bundles.kotest)

buildSrc/src/main/java/com/google/firebase/gradle/bomgenerator/BomGeneratorTask.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public abstract class BomGeneratorTask extends DefaultTask {
149149
"firebase-ml-model-interpreter",
150150
"firebase-perf-license",
151151
"firebase-plugins",
152+
"firebase-sessions",
152153
"firebase-storage-common",
153154
"firebase-storage-common-license",
154155
"firebase-storage-license",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=18.3.8
1+
version=18.4.0
22
latestReleasedVersion=18.3.7
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=18.3.8
1+
version=18.4.0
22
latestReleasedVersion=18.3.7

firebase-firestore/firebase-firestore.gradle

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ protobuf {
5050
}
5151
}
5252
}
53+
5354
android {
5455
adbOptions {
5556
timeOutInMs 60 * 1000
@@ -64,15 +65,23 @@ android {
6465
multiDexEnabled true
6566
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
6667
consumerProguardFiles 'proguard.txt'
68+
69+
def targetBackend = findProperty("targetBackend") ?: "emulator"
70+
buildConfigField("String", "TARGET_BACKEND", "\"$targetBackend\"")
71+
72+
def localProps = new Properties()
73+
74+
try {
75+
file("local.properties").withInputStream { localProps.load(it) }
76+
} catch (FileNotFoundException e) {
77+
}
6778
}
6879

6980
sourceSets {
7081
main {
7182
proto {
7283
srcDir 'src/proto'
7384
}
74-
java {
75-
}
7685
}
7786
test {
7887
java {
@@ -92,30 +101,12 @@ android {
92101
}
93102
testOptions.unitTests.includeAndroidResources = true
94103

95-
// Acceptable values are: 'emulator', 'qa', 'nightly', and 'prod'.
96-
ext.targetBackend = 'emulator'
97104
}
98105

99106
tasks.withType(Test) {
100107
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
101108
}
102109

103-
android.libraryVariants.all { variant ->
104-
if (findProperty('targetBackend')) {
105-
variant.buildConfigField("String", "TARGET_BACKEND", "\"${property("targetBackend")}\"")
106-
} else {
107-
// By default set the target backend to 'emulator'
108-
variant.buildConfigField("String", "TARGET_BACKEND", "\"emulator\"")
109-
}
110-
111-
def localProps = new Properties()
112-
113-
try {
114-
file("local.properties").withInputStream { localProps.load(it) }
115-
} catch (FileNotFoundException e) {
116-
}
117-
}
118-
119110
googleJavaFormat {
120111
exclude 'src/testUtil/java/com/google/firebase/firestore/testutil/Assert.java'
121112
exclude 'src/testUtil/java/com/google/firebase/firestore/testutil/ThrowingRunnable.java'
@@ -161,7 +152,6 @@ dependencies {
161152
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
162153
testImplementation 'com.google.guava:guava-testlib:12.0-rc2'
163154

164-
androidTestImplementation project(':firebase-firestore')
165155
androidTestImplementation 'junit:junit:4.13.2'
166156
androidTestImplementation("com.google.truth:truth:$googleTruthVersion"){
167157
exclude group: "org.codehaus.mojo", module: "animal-sniffer-annotations"
@@ -170,9 +160,9 @@ dependencies {
170160
androidTestImplementation 'org.mockito:mockito-android:2.25.0'
171161
androidTestImplementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
172162
androidTestImplementation "androidx.annotation:annotation:1.1.0"
173-
androidTestImplementation 'androidx.test:runner:1.2.0'
174-
androidTestImplementation 'androidx.test:rules:1.2.0'
175-
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
163+
androidTestImplementation 'androidx.test:runner:1.5.2'
164+
androidTestImplementation 'androidx.test:rules:1.5.0'
165+
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
176166
}
177167

178168
gradle.projectsEvaluated {

firebase-firestore/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=24.6.2
1+
version=24.7.0
22
latestReleasedVersion=24.6.1

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.firebase.firestore;
1616

17+
import static com.google.common.truth.Truth.assertThat;
1718
import static com.google.common.truth.Truth.assertWithMessage;
1819
import static com.google.firebase.firestore.remote.TestingHooksUtil.captureExistenceFilterMismatches;
1920
import static com.google.firebase.firestore.testutil.IntegrationTestUtil.isRunningAgainstEmulator;
@@ -32,6 +33,7 @@
3233
import static org.junit.Assert.assertFalse;
3334
import static org.junit.Assert.assertNull;
3435
import static org.junit.Assert.assertTrue;
36+
import static org.junit.Assume.assumeFalse;
3537
import static org.junit.Assume.assumeTrue;
3638

3739
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -42,6 +44,7 @@
4244
import com.google.firebase.firestore.remote.TestingHooksUtil.ExistenceFilterMismatchInfo;
4345
import com.google.firebase.firestore.testutil.EventAccumulator;
4446
import com.google.firebase.firestore.testutil.IntegrationTestUtil;
47+
import java.text.Normalizer;
4548
import java.util.ArrayList;
4649
import java.util.HashMap;
4750
import java.util.HashSet;
@@ -1169,6 +1172,160 @@ public void resumingAQueryShouldUseBloomFilterToAvoidFullRequery() throws Except
11691172
}
11701173
}
11711174

1175+
private static String unicodeNormalize(String s) {
1176+
return Normalizer.normalize(s, Normalizer.Form.NFC);
1177+
}
1178+
1179+
@Test
1180+
public void bloomFilterShouldCorrectlyEncodeComplexUnicodeCharacters() throws Exception {
1181+
assumeFalse(
1182+
"Skip this test when running against the Firestore emulator because the Firestore emulator "
1183+
+ "fails to send existence filters when queries are resumed (b/270731363), and even "
1184+
+ "if it did send an existence filter it probably wouldn't include a bloom filter.",
1185+
isRunningAgainstEmulator());
1186+
1187+
// Firestore does not do any Unicode normalization on the document IDs. Therefore, two document
1188+
// IDs that are canonically-equivalent (i.e. they visually appear identical) but are represented
1189+
// by a different sequence of Unicode code points are treated as distinct document IDs.
1190+
ArrayList<String> testDocIds = new ArrayList<>();
1191+
testDocIds.add("DocumentToDelete");
1192+
// The next two strings both end with "e" with an accent: the first uses the dedicated Unicode
1193+
// code point for this character, while the second uses the standard lowercase "e" followed by
1194+
// the accent combining character.
1195+
testDocIds.add("LowercaseEWithAcuteAccent_\u00E9");
1196+
testDocIds.add("LowercaseEWithAcuteAccent_\u0065\u0301");
1197+
// The next two strings both end with an "e" with two different accents applied via the
1198+
// following two combining characters. The combining characters are specified in a different
1199+
// order and Firestore treats these document IDs as unique, despite the order of the combining
1200+
// characters being irrelevant.
1201+
testDocIds.add("LowercaseEWithMultipleAccents_\u0065\u0301\u0327");
1202+
testDocIds.add("LowercaseEWithMultipleAccents_\u0065\u0327\u0301");
1203+
// The next string contains a character outside the BMP (the "basic multilingual plane"); that
1204+
// is, its code point is greater than 0xFFFF. Since "The Java programming language represents
1205+
// text in sequences of 16-bit code units, using the UTF-16 encoding" (according to the "Java
1206+
// Language Specification" at https://docs.oracle.com/javase/specs/jls/se11/html/index.html)
1207+
// this requires a surrogate pair, two 16-bit code units, to represent this character. Make sure
1208+
// that its presence is correctly tested in the bloom filter, which uses UTF-8 encoding.
1209+
testDocIds.add("Smiley_\uD83D\uDE00");
1210+
1211+
// Verify assumptions about the equivalence of strings in `testDocIds`.
1212+
assertThat(unicodeNormalize(testDocIds.get(1))).isEqualTo(unicodeNormalize(testDocIds.get(2)));
1213+
assertThat(unicodeNormalize(testDocIds.get(3))).isEqualTo(unicodeNormalize(testDocIds.get(4)));
1214+
assertThat(testDocIds.get(5).codePointAt(7)).isEqualTo(0x1F600);
1215+
1216+
// Create the mapping from document ID to document data for the document IDs specified in
1217+
// `testDocIds`.
1218+
Map<String, Map<String, Object>> testDocs = new HashMap<>();
1219+
for (String docId : testDocIds) {
1220+
testDocs.put(docId, map("foo", 42));
1221+
}
1222+
1223+
// Each iteration of the "while" loop below runs a single iteration of the test. The test will
1224+
// be run multiple times only if a bloom filter false positive occurs.
1225+
int attemptNumber = 0;
1226+
while (true) {
1227+
attemptNumber++;
1228+
1229+
// Create the documents whose names contain complex Unicode characters in a new collection.
1230+
CollectionReference collection = testCollectionWithDocs(testDocs);
1231+
1232+
// Run a query to populate the local cache with documents that have names with complex Unicode
1233+
// characters.
1234+
List<DocumentReference> createdDocuments = new ArrayList<>();
1235+
{
1236+
QuerySnapshot querySnapshot1 = waitFor(collection.get());
1237+
for (DocumentSnapshot documentSnapshot : querySnapshot1.getDocuments()) {
1238+
createdDocuments.add(documentSnapshot.getReference());
1239+
}
1240+
HashSet<String> createdDocumentIds = new HashSet<>();
1241+
for (DocumentSnapshot documentSnapshot : querySnapshot1.getDocuments()) {
1242+
createdDocumentIds.add(documentSnapshot.getId());
1243+
}
1244+
assertWithMessage("createdDocumentIds")
1245+
.that(createdDocumentIds)
1246+
.containsExactlyElementsIn(testDocIds);
1247+
}
1248+
1249+
// Delete one of the documents so that the next call to getDocs() will
1250+
// experience an existence filter mismatch. Do this deletion in a
1251+
// transaction, rather than using deleteDoc(), to avoid affecting the
1252+
// local cache.
1253+
waitFor(
1254+
collection
1255+
.getFirestore()
1256+
.runTransaction(
1257+
transaction -> {
1258+
DocumentReference documentToDelete = collection.document("DocumentToDelete");
1259+
DocumentSnapshot documentToDeleteSnapshot = transaction.get(documentToDelete);
1260+
assertWithMessage("documentToDeleteSnapshot.exists()")
1261+
.that(documentToDeleteSnapshot.exists())
1262+
.isTrue();
1263+
transaction.delete(documentToDelete);
1264+
return null;
1265+
}));
1266+
1267+
// Wait for 10 seconds, during which Watch will stop tracking the query and will send an
1268+
// existence filter rather than "delete" events when the query is resumed.
1269+
Thread.sleep(10000);
1270+
1271+
// Resume the query and save the resulting snapshot for verification. Use some internal
1272+
// testing hooks to "capture" the existence filter mismatches.
1273+
AtomicReference<QuerySnapshot> querySnapshot2Ref = new AtomicReference<>();
1274+
ArrayList<ExistenceFilterMismatchInfo> existenceFilterMismatches =
1275+
captureExistenceFilterMismatches(
1276+
() -> {
1277+
QuerySnapshot querySnapshot = waitFor(collection.get());
1278+
querySnapshot2Ref.set(querySnapshot);
1279+
});
1280+
QuerySnapshot querySnapshot2 = querySnapshot2Ref.get();
1281+
1282+
// Verify that the snapshot from the resumed query contains the expected documents; that is,
1283+
// that it contains the documents whose names contain complex Unicode characters and _not_ the
1284+
// document that was deleted.
1285+
HashSet<String> querySnapshot2DocumentIds = new HashSet<>();
1286+
for (DocumentSnapshot documentSnapshot : querySnapshot2.getDocuments()) {
1287+
querySnapshot2DocumentIds.add(documentSnapshot.getId());
1288+
}
1289+
HashSet<String> querySnapshot2ExpectedDocumentIds = new HashSet<>(testDocIds);
1290+
querySnapshot2ExpectedDocumentIds.remove("DocumentToDelete");
1291+
assertWithMessage("querySnapshot2DocumentIds")
1292+
.that(querySnapshot2DocumentIds)
1293+
.containsExactlyElementsIn(querySnapshot2ExpectedDocumentIds);
1294+
1295+
// Verify that Watch sent an existence filter with the correct counts.
1296+
assertWithMessage("Watch should have sent exactly 1 existence filter")
1297+
.that(existenceFilterMismatches)
1298+
.hasSize(1);
1299+
ExistenceFilterMismatchInfo existenceFilterMismatchInfo = existenceFilterMismatches.get(0);
1300+
assertWithMessage("localCacheCount")
1301+
.that(existenceFilterMismatchInfo.localCacheCount())
1302+
.isEqualTo(testDocIds.size());
1303+
assertWithMessage("existenceFilterCount")
1304+
.that(existenceFilterMismatchInfo.existenceFilterCount())
1305+
.isEqualTo(testDocIds.size() - 1);
1306+
1307+
// Verify that Watch sent a valid bloom filter.
1308+
ExistenceFilterBloomFilterInfo bloomFilter = existenceFilterMismatchInfo.bloomFilter();
1309+
assertWithMessage("The bloom filter specified in the existence filter")
1310+
.that(bloomFilter)
1311+
.isNotNull();
1312+
1313+
// Verify that the bloom filter was successfully used to avert a full requery. If a false
1314+
// positive occurred, which is statistically rare, but technically possible, then retry the
1315+
// entire test.
1316+
if (attemptNumber == 1 && !bloomFilter.applied()) {
1317+
continue;
1318+
}
1319+
1320+
assertWithMessage("bloom filter successfully applied with attemptNumber=" + attemptNumber)
1321+
.that(bloomFilter.applied())
1322+
.isTrue();
1323+
1324+
// Break out of the test loop now that the test passes.
1325+
break;
1326+
}
1327+
}
1328+
11721329
@Test
11731330
public void testOrQueries() {
11741331
Map<String, Map<String, Object>> testDocs =

firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,10 @@ private static FirebaseApp getDefaultFirebaseApp() {
114114
}
115115

116116
/**
117-
* Returns the default {@link FirebaseFirestore} instance associated with the default {@link
118-
* FirebaseApp}. Returns the same instance for all invocations. If no instance exists, initializes
119-
* a new instance with default settings.
117+
* Returns the default {@link FirebaseFirestore} instance for the default {@link FirebaseApp}.
118+
*
119+
* <p>Returns the same instance for all invocations. If no instance exists, initializes a new
120+
* instance with default settings.
120121
*
121122
* @returns The {@link FirebaseFirestore} instance.
122123
*/
@@ -126,9 +127,10 @@ public static FirebaseFirestore getInstance() {
126127
}
127128

128129
/**
129-
* Returns the default {@link FirebaseFirestore} instance that is associated with the provided
130-
* {@link FirebaseApp}. For a given {@link FirebaseApp}, invocation always returns the same
131-
* instance. If no instance exists, initializes a new instance with default settings.
130+
* Returns the default {@link FirebaseFirestore} instance for the provided {@link FirebaseApp}.
131+
*
132+
* <p>For a given {@link FirebaseApp}, invocation always returns the same instance. If no instance
133+
* exists, initializes a new instance with default settings.
132134
*
133135
* @param app - The {@link FirebaseApp} instance that the returned {@link FirebaseFirestore}
134136
* instance is associated with.
@@ -140,9 +142,10 @@ public static FirebaseFirestore getInstance(@NonNull FirebaseApp app) {
140142
}
141143

142144
/**
143-
* Returns the {@link FirebaseFirestore} instance that is associated with the default {@link
144-
* FirebaseApp}. Returns the same instance for all invocations given the same database parameter.
145-
* If no instance exists, initializes a new instance with default settings.
145+
* Returns the {@link FirebaseFirestore} instance for the default {@link FirebaseApp}.
146+
*
147+
* <p>Returns the same instance for all invocations given the same database parameter. If no
148+
* instance exists, initializes a new instance with default settings.
146149
*
147150
* @param database - The name of database.
148151
* @returns The {@link FirebaseFirestore} instance.
@@ -153,10 +156,10 @@ public static FirebaseFirestore getInstance(@NonNull String database) {
153156
}
154157

155158
/**
156-
* Returns the {@link FirebaseFirestore} instance that is associated with the provided {@link
157-
* FirebaseApp}. Returns the same instance for all invocations given the same {@link FirebaseApp}
158-
* and database parameter. If no instance exists, initializes a new instance with default
159-
* settings.
159+
* Returns the {@link FirebaseFirestore} instance for the provided {@link FirebaseApp}.
160+
*
161+
* <p>Returns the same instance for all invocations given the same {@link FirebaseApp} and
162+
* database parameter. If no instance exists, initializes a new instance with default settings.
160163
*
161164
* @param app - The {@link FirebaseApp} instance that the returned {@link FirebaseFirestore}
162165
* instance is associated with.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version=23.1.3
1+
version=23.2.0
22
latestReleasedVersion=23.1.2
33
android.enableUnitTestBinaryResources=true

firebase-messaging/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
[FAQ](https://firebase.google.com/support/faq#fcm-23-deprecation) for more
44
details.
55

6+
* [changed] Changed to finish a background broadcast after the message has been
7+
handled, subject to a timeout. This keeps the `FirebaseMessagingService`'s
8+
process in an active state while it is handling an FCM message, up to the
9+
20 seconds allowed.
10+
611
# 23.1.2
712
* [fixed] Fixed a breakage related to Jetpack core library related to an
813
[upstream update](https://android-review.googlesource.com/c/platform/frameworks/support/+/2399893).

firebase-messaging/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version=23.1.3
1+
version=23.2.0
22
latestReleasedVersion=23.1.2
33
android.enableUnitTestBinaryResources=true

0 commit comments

Comments
 (0)