Builder instance is returned so subsequent calls can be chained.
+ */
+ public Builder setWriteTimeout(int writeTimeout) {
+ this.writeTimeout = writeTimeout;
+ return this;
+ }
+
/**
* Builds the {@link FirebaseOptions} instance from the previously set options.
*
diff --git a/src/main/java/com/google/firebase/ImplFirebaseTrampolines.java b/src/main/java/com/google/firebase/ImplFirebaseTrampolines.java
index 3a7f6499a..0d3008b18 100644
--- a/src/main/java/com/google/firebase/ImplFirebaseTrampolines.java
+++ b/src/main/java/com/google/firebase/ImplFirebaseTrampolines.java
@@ -22,6 +22,8 @@
import com.google.api.core.ApiFutures;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.firestore.FirestoreOptions;
+import com.google.firebase.auth.internal.Utils;
+import com.google.firebase.internal.EmulatorCredentials;
import com.google.firebase.internal.FirebaseService;
import com.google.firebase.internal.NonNull;
@@ -41,6 +43,9 @@ public final class ImplFirebaseTrampolines {
private ImplFirebaseTrampolines() {}
public static GoogleCredentials getCredentials(@NonNull FirebaseApp app) {
+ if (Utils.isEmulatorMode()) {
+ return new EmulatorCredentials();
+ }
return app.getOptions().getCredentials();
}
diff --git a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
index d1b4a513e..44fe9b7d2 100644
--- a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
+++ b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
@@ -600,9 +600,10 @@ private CallableOperationA Google Cloud project ID is required to access Firestore. FirestoreClient determines the
@@ -32,7 +35,7 @@ public class FirestoreClient {
private final Firestore firestore;
- private FirestoreClient(FirebaseApp app) {
+ private FirestoreClient(FirebaseApp app, String databaseId) {
checkNotNull(app, "FirebaseApp must not be null");
String projectId = ImplFirebaseTrampolines.getProjectId(app);
checkArgument(!Strings.isNullOrEmpty(projectId),
@@ -47,16 +50,17 @@ private FirestoreClient(FirebaseApp app) {
.setCredentialsProvider(
FixedCredentialsProvider.create(ImplFirebaseTrampolines.getCredentials(app)))
.setProjectId(projectId)
+ .setDatabaseId(databaseId)
.build()
.getService();
}
/**
- * Returns the Firestore instance associated with the default Firebase app. Returns the same
- * instance for all invocations. The Firestore instance and all references obtained from it
+ * Returns the default Firestore instance associated with the default Firebase app. Returns the
+ * same instance for all invocations. The Firestore instance and all references obtained from it
* becomes unusable, once the default app is deleted.
*
- * @return A non-null {@code Firestore}
+ * @return A non-null {@code Firestore}
* instance.
*/
@NonNull
@@ -65,42 +69,97 @@ public static Firestore getFirestore() {
}
/**
- * Returns the Firestore instance associated with the specified Firebase app. For a given app,
- * always returns the same instance. The Firestore instance and all references obtained from it
- * becomes unusable, once the specified app is deleted.
+ * Returns the default Firestore instance associated with the specified Firebase app. For a given
+ * app, invocation always returns the same instance. The Firestore instance and all references
+ * obtained from it becomes unusable, once the specified app is deleted.
*
* @param app A non-null {@link FirebaseApp}.
- * @return A non-null {@code Firestore}
+ * @return A non-null {@code Firestore}
* instance.
*/
@NonNull
public static Firestore getFirestore(FirebaseApp app) {
- return getInstance(app).firestore;
+ final FirestoreOptions firestoreOptions = ImplFirebaseTrampolines.getFirestoreOptions(app);
+ return getFirestore(app, firestoreOptions == null ? null : firestoreOptions.getDatabaseId());
+ }
+
+ /**
+ * Returns the Firestore instance associated with the specified Firebase app. Returns the same
+ * instance for all invocations given the same app and database parameter. The Firestore instance
+ * and all references obtained from it becomes unusable, once the specified app is deleted.
+ *
+ * @param app A non-null {@link FirebaseApp}.
+ * @param database - The name of database.
+ * @return A non-null {@code Firestore}
+ * instance.
+ */
+ @NonNull
+ public static Firestore getFirestore(FirebaseApp app, String database) {
+ return getInstance(app, database).firestore;
+ }
+
+ /**
+ * Returns the Firestore instance associated with the default Firebase app. Returns the same
+ * instance for all invocations given the same database parameter. The Firestore instance and all
+ * references obtained from it becomes unusable, once the default app is deleted.
+ *
+ * @param database - The name of database.
+ * @return A non-null {@code Firestore}
+ * instance.
+ */
+ @NonNull
+ public static Firestore getFirestore(String database) {
+ return getFirestore(FirebaseApp.getInstance(), database);
}
- private static synchronized FirestoreClient getInstance(FirebaseApp app) {
+ private static synchronized FirestoreClient getInstance(FirebaseApp app, String database) {
FirestoreClientService service = ImplFirebaseTrampolines.getService(app,
SERVICE_ID, FirestoreClientService.class);
if (service == null) {
service = ImplFirebaseTrampolines.addService(app, new FirestoreClientService(app));
}
- return service.getInstance();
+ return service.getInstance().get(database);
}
private static final String SERVICE_ID = FirestoreClient.class.getName();
- private static class FirestoreClientService extends FirebaseService If the {@code dryRun} option is set to true, the message will not be actually sent. Instead
* FCM performs all the necessary validations and emulates the send operation. The {@code dryRun}
- * option is useful for determining whether an FCM registration has been deleted. However, it
+ * option is useful for determining whether an FCM registration has been deleted. However, it
* cannot be used to validate APNs tokens.
*
* @param message A non-null {@link Message} to be sent.
@@ -139,6 +144,200 @@ protected String execute() throws FirebaseMessagingException {
};
}
+ /**
+ * Sends each message in the given list via Firebase Cloud Messaging.
+ * Unlike {@link #sendAll(List)}, this method makes an HTTP call for each message in the
+ * given array.
+ *
+ * The list of responses obtained by calling {@link BatchResponse#getResponses()} on the return
+ * value is in the same order as the input list.
+ *
+ * @param messages A non-null, non-empty list containing up to 500 messages.
+ * @return A {@link BatchResponse} indicating the result of the operation.
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
+ * failure, meaning that none of the messages in the list could be sent. Partial failures or
+ * no failures are only indicated by a {@link BatchResponse}.
+ */
+ public BatchResponse sendEach(@NonNull List If the {@code dryRun} option is set to true, the message will not be actually sent. Instead
+ * FCM performs all the necessary validations, and emulates the send operation. The {@code dryRun}
+ * option is useful for determining whether an FCM registration has been deleted. But it cannot be
+ * used to validate APNs tokens.
+ *
+ * The list of responses obtained by calling {@link BatchResponse#getResponses()} on the return
+ * value is in the same order as the input list.
+ *
+ * @param messages A non-null, non-empty list containing up to 500 messages.
+ * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
+ * @return A {@link BatchResponse} indicating the result of the operation.
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
+ * failure, meaning that none of the messages in the list could be sent. Partial failures or
+ * no failures are only indicated by a {@link BatchResponse}.
+ */
+ public BatchResponse sendEach(
+ @NonNull List This method uses the {@link #sendEach(List)} API under the hood to send the given
+ * message to all the target recipients. The list of responses obtained by calling
+ * {@link BatchResponse#getResponses()} on the return value is in the same order as the
+ * tokens in the {@link MulticastMessage}.
+ *
+ * @param message A non-null {@link MulticastMessage}
+ * @return A {@link BatchResponse} indicating the result of the operation.
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
+ * failure, meaning that none of the messages in the list could be sent. Partial failures or
+ * no failures are only indicated by a {@link BatchResponse}.
+ */
+ public BatchResponse sendEachForMulticast(
+ @NonNull MulticastMessage message) throws FirebaseMessagingException {
+ return sendEachForMulticast(message, false);
+ }
+
+ /**
+ * Sends the given multicast message to all the FCM registration tokens specified in it.
+ *
+ * If the {@code dryRun} option is set to true, the message will not be actually sent. Instead
+ * FCM performs all the necessary validations, and emulates the send operation. The {@code dryRun}
+ * option is useful for determining whether an FCM registration has been deleted. But it cannot be
+ * used to validate APNs tokens.
+ *
+ * This method uses the {@link #sendEach(List)} API under the hood to send the given
+ * message to all the target recipients. The list of responses obtained by calling
+ * {@link BatchResponse#getResponses()} on the return value is in the same order as the
+ * tokens in the {@link MulticastMessage}.
+ *
+ * @param message A non-null {@link MulticastMessage}.
+ * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
+ * @return A {@link BatchResponse} indicating the result of the operation.
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
+ * failure, meaning that none of the messages in the list could be sent. Partial failures or
+ * no failures are only indicated by a {@link BatchResponse}.
+ */
+ public BatchResponse sendEachForMulticast(@NonNull MulticastMessage message, boolean dryRun)
+ throws FirebaseMessagingException {
+ checkNotNull(message, "multicast message must not be null");
+ return sendEach(message.getMessageList(), dryRun);
+ }
+
+ /**
+ * Similar to {@link #sendEachForMulticast(MulticastMessage)} but performs the operation
+ * asynchronously.
+ *
+ * @param message A non-null {@link MulticastMessage}.
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
+ * the messages have been sent.
+ */
+ public ApiFutureFirebaseOptions,
* or if the bucket does not exist.
@@ -84,7 +84,7 @@ public Bucket bucket() {
* Returns a cloud storage Bucket instance for the specified bucket name.
*
* @param name a non-null, non-empty bucket name.
- * @return a cloud storage {@code Bucket}
+ * @return a cloud storage {@code Bucket}
* instance.
* @throws IllegalArgumentException If the bucket name is null, empty, or if the specified
* bucket does not exist.
diff --git a/src/main/java/com/google/firebase/database/FirebaseDatabase.java b/src/main/java/com/google/firebase/database/FirebaseDatabase.java
index 306ce9274..e59cd38fa 100644
--- a/src/main/java/com/google/firebase/database/FirebaseDatabase.java
+++ b/src/main/java/com/google/firebase/database/FirebaseDatabase.java
@@ -35,6 +35,7 @@
import com.google.firebase.database.utilities.ParsedUrl;
import com.google.firebase.database.utilities.Utilities;
import com.google.firebase.database.utilities.Validation;
+import com.google.firebase.internal.EmulatorCredentials;
import com.google.firebase.internal.FirebaseService;
import com.google.firebase.internal.SdkUtils;
@@ -406,26 +407,4 @@ public void destroy() {
instance.destroy();
}
}
-
- private static class EmulatorCredentials extends GoogleCredentials {
-
- EmulatorCredentials() {
- super(newToken());
- }
-
- private static AccessToken newToken() {
- return new AccessToken("owner",
- new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)));
- }
-
- @Override
- public AccessToken refreshAccessToken() {
- return newToken();
- }
-
- @Override
- public Map> responsesFuture = ApiFutures.allAsList(list);
+
+ // Chain this future to wrap the eventual responses in a BatchResponse without blocking
+ // the main thread. This uses the current thread to execute, but since the transformation
+ // function is non-blocking the transformation itself is also non-blocking.
+ return ApiFutures.transform(
+ responsesFuture,
+ (responses) -> {
+ return new BatchResponseImpl(responses);
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ private CallableOperation