Skip to content

Commit 04167a5

Browse files
committed
Merge branch 'master' into wuandy/ActuallySkipOverlayMigration
# Conflicts: # firebase-firestore/CHANGELOG.md
2 parents b1c2aa6 + 8394f24 commit 04167a5

File tree

41 files changed

+1150
-379
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1150
-379
lines changed

appcheck/firebase-appcheck-playintegrity/firebase-appcheck-playintegrity.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ dependencies {
4848
implementation 'com.google.android.gms:play-services-tasks:18.0.1'
4949
implementation 'com.google.android.play:integrity:1.0.1'
5050

51+
javadocClasspath 'com.google.auto.value:auto-value-annotations:1.6.6'
52+
5153
testImplementation 'junit:junit:4.13.2'
5254
testImplementation 'org.mockito:mockito-core:3.4.6'
5355
testImplementation "com.google.truth:truth:$googleTruthVersion"

firebase-appdistribution/test-app/src/main/java/com/googletest/firebase/appdistribution/testapp/MainActivity.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,15 @@ class MainActivity : AppCompatActivity() {
122122
executorService.execute {
123123
firebaseAppDistribution
124124
.checkForNewRelease()
125-
.addOnSuccessListener { release = it }
125+
.addOnSuccessListener {
126+
release = it
127+
setupUI(
128+
isSignedIn = firebaseAppDistribution.isTesterSignedIn,
129+
isUpdateAvailable = release != null,
130+
release = release)
131+
}
126132
.addOnFailureListener { failureListener(it) }
127133
}
128-
setupUI(
129-
isSignedIn = firebaseAppDistribution.isTesterSignedIn,
130-
isUpdateAvailable = release != null,
131-
release = release)
132134
}
133135

134136
signOutButton.setOnClickListener {
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources xmlns:tools="http://schemas.android.com/tools"
3-
tools:keep="@string/google_app_id,@string/gcm_defaultSenderId,@string/google_api_key,@string/firebase_database_url,@string/ga_trackingId,@string/google_storage_bucket,@string/project_id"
4-
tools:shrinkMode="strict" />
3+
tools:keep="@string/google_app_id,@string/gcm_defaultSenderId,@string/google_api_key,@string/firebase_database_url,@string/ga_trackingId,@string/google_storage_bucket,@string/project_id" />

firebase-firestore/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ by opting into a release at
33
[go/firebase-android-release](http:go/firebase-android-release) (Googlers only).
44

55
# 24.1.2
6+
# Unreleased
7+
- [changed] Added `TransactionOptions` to control how many times a transaction
8+
will retry commits before failing.
69
- [fixed] Fixed an issue where patching multiple fields shadows each other (#3528).
710
- [feature] Added customization support for `FirebaseFirestore.runTransaction`.
811

@@ -18,6 +21,7 @@ by opting into a release at
1821
JSON index definition exported by the Firestore CLI. Queries against the
1922
cache are executed using an index once the asynchronous operation to generate
2023
the index entries completes.
24+
- [fixed] Fixed missing document fields issue with offline overlays (#3528)
2125

2226
# 24.0.2
2327
- [fixed] Fixed an issue of long grpc reconnection period, when App moves to

firebase-firestore/api.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ package com.google.firebase.firestore {
152152
method @NonNull public com.google.firebase.firestore.LoadBundleTask loadBundle(@NonNull java.nio.ByteBuffer);
153153
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> runBatch(@NonNull com.google.firebase.firestore.WriteBatch.Function);
154154
method @NonNull public <TResult> com.google.android.gms.tasks.Task<TResult> runTransaction(@NonNull com.google.firebase.firestore.Transaction.Function<TResult>);
155+
method @NonNull public <TResult> com.google.android.gms.tasks.Task<TResult> runTransaction(@NonNull com.google.firebase.firestore.TransactionOptions, @NonNull com.google.firebase.firestore.Transaction.Function<TResult>);
155156
method public void setFirestoreSettings(@NonNull com.google.firebase.firestore.FirebaseFirestoreSettings);
156157
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setIndexConfiguration(@NonNull String);
157158
method public static void setLoggingEnabled(boolean);
@@ -387,6 +388,17 @@ package com.google.firebase.firestore {
387388
method @Nullable public TResult apply(@NonNull com.google.firebase.firestore.Transaction) throws com.google.firebase.firestore.FirebaseFirestoreException;
388389
}
389390

391+
public final class TransactionOptions {
392+
method public int getMaxAttempts();
393+
}
394+
395+
public static final class TransactionOptions.Builder {
396+
ctor public TransactionOptions.Builder();
397+
ctor public TransactionOptions.Builder(@NonNull com.google.firebase.firestore.TransactionOptions);
398+
method @NonNull public com.google.firebase.firestore.TransactionOptions build();
399+
method @NonNull public com.google.firebase.firestore.TransactionOptions.Builder setMaxAttempts(int);
400+
}
401+
390402
public class WriteBatch {
391403
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> commit();
392404
method @NonNull public com.google.firebase.firestore.WriteBatch delete(@NonNull com.google.firebase.firestore.DocumentReference);

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

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.junit.Assert.assertEquals;
2222
import static org.junit.Assert.assertFalse;
2323
import static org.junit.Assert.assertNotNull;
24+
import static org.junit.Assert.assertThrows;
2425
import static org.junit.Assert.assertTrue;
2526
import static org.junit.Assert.fail;
2627

@@ -29,7 +30,6 @@
2930
import com.google.android.gms.tasks.TaskCompletionSource;
3031
import com.google.android.gms.tasks.Tasks;
3132
import com.google.firebase.firestore.FirebaseFirestoreException.Code;
32-
import com.google.firebase.firestore.core.TransactionRunner;
3333
import com.google.firebase.firestore.testutil.IntegrationTestUtil;
3434
import com.google.firebase.firestore.util.AsyncQueue.TimerId;
3535
import java.util.ArrayList;
@@ -651,7 +651,38 @@ public void testMakesDefaultMaxAttempts() {
651651

652652
Exception e = waitForException(transactionTask);
653653
assertEquals(Code.FAILED_PRECONDITION, ((FirebaseFirestoreException) e).getCode());
654-
assertEquals(TransactionRunner.DEFAULT_MAX_ATTEMPTS_COUNT, count.get());
654+
assertEquals(TransactionOptions.DEFAULT_MAX_ATTEMPTS_COUNT, count.get());
655+
}
656+
657+
@Test
658+
public void testMakesOptionSpecifiedMaxAttempts() {
659+
TransactionOptions options = new TransactionOptions.Builder().setMaxAttempts(1).build();
660+
661+
FirebaseFirestore firestore = testFirestore();
662+
DocumentReference doc1 = firestore.collection("counters").document();
663+
AtomicInteger count = new AtomicInteger(0);
664+
waitFor(doc1.set(map("count", 15)));
665+
Task<Void> transactionTask =
666+
firestore.runTransaction(
667+
options,
668+
transaction -> {
669+
// Get the first doc.
670+
transaction.get(doc1);
671+
// Do a write outside of the transaction to cause the transaction to fail.
672+
waitFor(doc1.set(map("count", 1234 + count.incrementAndGet())));
673+
return null;
674+
});
675+
676+
Exception e = waitForException(transactionTask);
677+
assertEquals(Code.FAILED_PRECONDITION, ((FirebaseFirestoreException) e).getCode());
678+
assertEquals(options.getMaxAttempts(), count.get());
679+
}
680+
681+
@Test
682+
public void testTransactionOptionsZeroMaxAttempts_shouldThrowIllegalArgumentException() {
683+
assertThrows(
684+
IllegalArgumentException.class,
685+
() -> new TransactionOptions.Builder().setMaxAttempts(0).build());
655686
}
656687

657688
@Test

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

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,10 @@ public Query collectionGroup(@NonNull String collectionId) {
405405
}
406406

407407
/**
408-
* Executes the given updateFunction and then attempts to commit the changes applied within the
409-
* transaction. If any document read within the transaction has changed, the updateFunction will
410-
* be retried. If it fails to commit after 5 attempts, the transaction will fail.
408+
* Executes the given {@code updateFunction} and then attempts to commit the changes applied
409+
* within the transaction. If any document read within the transaction has changed, the
410+
* updateFunction will be retried. If it fails to commit after 5 attempts (the default failure
411+
* limit), the transaction will fail.
411412
*
412413
* <p>The maximum number of writes allowed in a single transaction is 500, but note that each
413414
* usage of {@link FieldValue#serverTimestamp()}, {@link FieldValue#arrayUnion(Object...)}, {@link
@@ -419,7 +420,7 @@ public Query collectionGroup(@NonNull String collectionId) {
419420
* @return The task returned from the updateFunction.
420421
*/
421422
private <ResultT> Task<ResultT> runTransaction(
422-
Transaction.Function<ResultT> updateFunction, Executor executor) {
423+
TransactionOptions options, Transaction.Function<ResultT> updateFunction, Executor executor) {
423424
ensureClientConfigured();
424425

425426
// We wrap the function they provide in order to
@@ -434,23 +435,43 @@ private <ResultT> Task<ResultT> runTransaction(
434435
updateFunction.apply(
435436
new Transaction(internalTransaction, FirebaseFirestore.this)));
436437

437-
return client.transaction(wrappedUpdateFunction);
438+
return client.transaction(options, wrappedUpdateFunction);
438439
}
439440

440441
/**
441-
* Executes the given updateFunction and then attempts to commit the changes applied within the
442-
* transaction. If any document read within the transaction has changed, the updateFunction will
443-
* be retried. If it fails to commit after 5 attempts, the transaction will fail.
442+
* Executes the given {@code updateFunction} and then attempts to commit the changes applied
443+
* within the transaction. If any document read within the transaction has changed, the
444+
* updateFunction will be retried. If it fails to commit after 5 attempts (the default failure
445+
* limit), the transaction will fail. To have a different number of retries, use the {@link
446+
* FirebaseFirestore#runTransaction(TransactionOptions, Transaction.Function)} method instead.
444447
*
445448
* @param updateFunction The function to execute within the transaction context.
446449
* @return The task returned from the updateFunction.
447450
*/
448451
@NonNull
449452
public <TResult> Task<TResult> runTransaction(
450453
@NonNull Transaction.Function<TResult> updateFunction) {
454+
return runTransaction(TransactionOptions.DEFAULT, updateFunction);
455+
}
456+
457+
/**
458+
* Executes the given {@code updateFunction} and then attempts to commit the changes applied
459+
* within the transaction. If any document read within the transaction has changed, the
460+
* updateFunction will be retried. If it fails to commit after the maxmimum number of attempts
461+
* specified in transactionOptions, the transaction will fail.
462+
*
463+
* @param options The transaction options for controlling execution.
464+
* @param updateFunction The function to execute within the transaction context.
465+
* @return The task returned from the updateFunction.
466+
*/
467+
@NonNull
468+
public <TResult> Task<TResult> runTransaction(
469+
@NonNull TransactionOptions options, @NonNull Transaction.Function<TResult> updateFunction) {
451470
checkNotNull(updateFunction, "Provided transaction update function must not be null.");
452471
return runTransaction(
453-
updateFunction, com.google.firebase.firestore.core.Transaction.getDefaultExecutor());
472+
options,
473+
updateFunction,
474+
com.google.firebase.firestore.core.Transaction.getDefaultExecutor());
454475
}
455476

456477
/**
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore;
16+
17+
import androidx.annotation.NonNull;
18+
19+
/**
20+
* Options to customize transaction behavior for {@link
21+
* FirebaseFirestore#runTransaction(TransactionOptions, Transaction.Function)}.
22+
*/
23+
public final class TransactionOptions {
24+
25+
static final TransactionOptions DEFAULT = new TransactionOptions.Builder().build();
26+
static final int DEFAULT_MAX_ATTEMPTS_COUNT = 5;
27+
28+
private final int maxAttempts;
29+
30+
private TransactionOptions(int maxAttempts) {
31+
this.maxAttempts = maxAttempts;
32+
}
33+
34+
/** A Builder for creating {@code TransactionOptions}. */
35+
public static final class Builder {
36+
private int maxAttempts = DEFAULT_MAX_ATTEMPTS_COUNT;
37+
38+
/** Constructs a new {@code TransactionOptions} Builder object. */
39+
public Builder() {}
40+
41+
/**
42+
* Constructs a new {@code TransactionOptions} Builder based on an existing {@code
43+
* TransactionOptions} object.
44+
*/
45+
public Builder(@NonNull TransactionOptions options) {
46+
maxAttempts = options.maxAttempts;
47+
}
48+
49+
/**
50+
* Set maximum number of attempts to commit, after which transaction fails.
51+
*
52+
* <p>The default value is 5. Setting the value to less than 1 will result in an {@link
53+
* IllegalArgumentException}.
54+
*
55+
* @return This builder
56+
*/
57+
@NonNull
58+
public Builder setMaxAttempts(int maxAttempts) {
59+
if (maxAttempts < 1) throw new IllegalArgumentException("Max attempts must be at least 1");
60+
this.maxAttempts = maxAttempts;
61+
return this;
62+
}
63+
64+
/**
65+
* Build the {@code TransactionOptions} object.
66+
*
67+
* @return The built {@code TransactionOptions} object
68+
*/
69+
@NonNull
70+
public TransactionOptions build() {
71+
return new TransactionOptions(maxAttempts);
72+
}
73+
}
74+
75+
/**
76+
* Get maximum number of attempts to commit, after which transaction fails. Default is 5.
77+
*
78+
* @return The maximum number of attempts
79+
*/
80+
public int getMaxAttempts() {
81+
return maxAttempts;
82+
}
83+
84+
@Override
85+
public boolean equals(Object o) {
86+
if (this == o) return true;
87+
if (o == null || getClass() != o.getClass()) return false;
88+
89+
TransactionOptions that = (TransactionOptions) o;
90+
91+
return maxAttempts == that.maxAttempts;
92+
}
93+
94+
@Override
95+
public int hashCode() {
96+
return maxAttempts;
97+
}
98+
99+
@Override
100+
public String toString() {
101+
return "TransactionOptions{" + "maxAttempts=" + maxAttempts + '}';
102+
}
103+
}

firebase-firestore/src/main/java/com/google/firebase/firestore/core/FirestoreClient.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.firebase.firestore.FirebaseFirestoreException.Code;
2727
import com.google.firebase.firestore.FirebaseFirestoreSettings;
2828
import com.google.firebase.firestore.LoadBundleTask;
29+
import com.google.firebase.firestore.TransactionOptions;
2930
import com.google.firebase.firestore.auth.CredentialsProvider;
3031
import com.google.firebase.firestore.auth.User;
3132
import com.google.firebase.firestore.bundle.BundleReader;
@@ -228,10 +229,12 @@ public Task<Void> write(final List<Mutation> mutations) {
228229
}
229230

230231
/** Tries to execute the transaction in updateFunction. */
231-
public <TResult> Task<TResult> transaction(Function<Transaction, Task<TResult>> updateFunction) {
232+
public <TResult> Task<TResult> transaction(
233+
TransactionOptions options, Function<Transaction, Task<TResult>> updateFunction) {
232234
this.verifyNotTerminated();
233235
return AsyncQueue.callTask(
234-
asyncQueue.getExecutor(), () -> syncEngine.transaction(asyncQueue, updateFunction));
236+
asyncQueue.getExecutor(),
237+
() -> syncEngine.transaction(asyncQueue, options, updateFunction));
235238
}
236239

237240
/**

firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.firebase.firestore.FirebaseFirestoreException;
2727
import com.google.firebase.firestore.LoadBundleTask;
2828
import com.google.firebase.firestore.LoadBundleTaskProgress;
29+
import com.google.firebase.firestore.TransactionOptions;
2930
import com.google.firebase.firestore.auth.User;
3031
import com.google.firebase.firestore.bundle.BundleElement;
3132
import com.google.firebase.firestore.bundle.BundleLoader;
@@ -307,8 +308,10 @@ private void addUserCallback(int batchId, TaskCompletionSource<Void> userTask) {
307308
* <p>The Task returned is resolved when the transaction is fully committed.
308309
*/
309310
public <TResult> Task<TResult> transaction(
310-
AsyncQueue asyncQueue, Function<Transaction, Task<TResult>> updateFunction) {
311-
return new TransactionRunner<TResult>(asyncQueue, remoteStore, updateFunction).run();
311+
AsyncQueue asyncQueue,
312+
TransactionOptions options,
313+
Function<Transaction, Task<TResult>> updateFunction) {
314+
return new TransactionRunner<TResult>(asyncQueue, remoteStore, options, updateFunction).run();
312315
}
313316

314317
/** Called by FirestoreClient to notify us of a new remote event. */

0 commit comments

Comments
 (0)